notIntermediate Examples

Logical NOT operator; inverts a boolean value

not in boolean contexts

Using not for clean conditional logic.

python
# Double negation and bool()
x = 42
print(not not x)     # Same as bool(x)
print(bool(x))       # Clearer way

# not vs !=
items = [1, 2, 3]
# These are different:
print(not items == [])   # not (items == []) = not False = True
print(items != [])        # True (preferred)

# De Morgan's laws
a, b = True, False
print(f"not (a or b) = {not (a or b)}")
print(f"(not a) and (not b) = {(not a) and (not b)}")
print(f"not (a and b) = {not (a and b)}")
print(f"(not a) or (not b) = {(not a) or (not b)}")
Expected Output
True
True
True
True
not (a or b) = False
(not a) and (not b) = False
not (a and b) = True
(not a) or (not b) = True

'not' always returns a boolean. Use it for readability, but prefer 'is not', 'not in', and '!=' over 'not ... is', 'not ... in', and 'not ... =='.

not with custom objects

How not interacts with __bool__ and __len__.

python
class Box:
    def __init__(self, items):
        self.items = items

    def __bool__(self):
        return len(self.items) > 0

    def __repr__(self):
        return f"Box({self.items})"

empty_box = Box([])
full_box = Box([1, 2, 3])

print(f"not {empty_box}: {not empty_box}")
print(f"not {full_box}: {not full_box}")

# Without __bool__, not uses __len__
class Stack:
    def __init__(self):
        self.data = []
    def push(self, x):
        self.data.append(x)
    def __len__(self):
        return len(self.data)

s = Stack()
print(f"Empty stack: not s = {not s}")
s.push(1)
print(f"Non-empty stack: not s = {not s}")
Expected Output
not Box([]): True
not Box([1, 2, 3]): False
Empty stack: not s = True
Non-empty stack: not s = False

'not' calls __bool__() on the object. If __bool__ isn't defined, it falls back to __len__. If neither exists, the object is always truthy (not returns False).

Want to try these examples interactively?

Open Intermediate Playground