Definition of the not operator in Python
The not operator is one of the three logical (or boolean) operators in Python, alongside and and or. Its role is simple but fundamental: it inverts the truth value of an expression. If an expression evaluates to True, not transforms it into False, and vice versa.
In programming, logical negation is used constantly: checking that a condition is not met, inverting a boolean flag, filtering elements that don't match a criterion, etc. If you want to deepen your Python skills and master all its operators, our complete Python course will guide you step by step.
Unlike arithmetic or comparison operators, not is a unary operator: it only applies to a single value, the one immediately following it.
Syntax and basic behavior
The syntax of not is remarkably simple:
not expressionThe operator first evaluates the expression that follows it, then returns the inverse boolean value. Let's see this with the most basic cases:
print(not True) # False
print(not False) # TrueThis is the fundamental behavior: not True gives False and not False gives True. Here is the complete truth table for the not operator:
| Expression | Result |
|---|---|
not True | False |
not False | True |
It's as simple as that. But the true power of not appears when it is combined with more complex expressions and the concept of truthy and falsy values.
Truthy and falsy values with not
In Python, every object has an implicit truth value. We talk about truthy values (evaluated as True) and falsy values (evaluated as False). The not operator relies on this implicit evaluation to work.
Falsy values in Python
The following values are considered falsy, meaning they evaluate to False in a boolean context:
| Value | not value | Explanation |
|---|---|---|
None | True | The absence of value |
False | True | The boolean false |
0 | True | The integer zero |
0.0 | True | The float zero |
"" | True | The empty string |
[] | True | The empty list |
() | True | The empty tuple |
{} | True | The empty dict |
set() | True | The empty set |
Let's verify this with a concrete example:
# All these expressions return True
print(not None) # True
print(not 0) # True
print(not 0.0) # True
print(not "") # True
print(not []) # True
print(not ()) # True
print(not {}) # True
Truthy values
Conversely, any value that is not falsy is truthy. Applying not to a truthy value returns False:
print(not 42) # False
print(not "Hello") # False
print(not [1, 2, 3]) # False
print(not {"key": "val"}) # FalseThis mechanism is extremely useful for quickly checking if a collection is empty, if a variable is defined, or if a numeric value is non-zero.
Practical usage examples
Let's now see how not is used in real-world Python development situations.
Checking if a list is empty
One of the most common uses of not is checking if a collection (list, dict, set, etc.) is empty:
cart = []
if not cart:
print("Your cart is empty.")
else:
print(f"You have {len(cart)} item(s).")
# Result: Your cart is empty.This approach is considered Pythonic. It is preferred over if len(cart) == 0: because it is more readable and more idiomatic.
Checking if a variable is not None
user = None
if not user:
print("No user logged in.")
# Redirect to login page
else:
print(f"Welcome, {user}!")Be careful: not user will also be True if user is an empty string "" or the number 0. If you need to specifically check for the value None, use if user is None: instead.
Inverting a condition in a loop
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Filter numbers that are NOT even
odd_numbers = [n for n in numbers if not n % 2 == 0]
print(odd_numbers) # [1, 3, 5, 7, 9]In this example, not n % 2 == 0 inverts the "is even" condition to keep only odd numbers. You could also write n % 2 != 0, but using not is sometimes more readable for complex conditions.
Combining not with and and or
The not operator can be combined with the and and or operators to build complex logical conditions:
age = 25
is_student = False
is_member = True
# Free access if member OR if student under 26
# But NOT if both conditions are false
if is_member or (is_student and age < 26):
print("Free access")
else:
print("Paid access")
# Check that a user is NOT a student AND NOT a member
if not is_student and not is_member:
print("No benefits available")
else:
print("You have benefits")
Using not in
The not in combination is a membership test operator that checks whether an element is not present in a sequence:
allowed_fruits = ["apple", "banana", "orange", "kiwi"]
chosen_fruit = "mango"
if chosen_fruit not in allowed_fruits:
print(f"Sorry, {chosen_fruit} is not available.")
else:
print(f"Excellent choice: {chosen_fruit}!")
# Result: Sorry, mango is not available.
Using is not
Similarly, is not allows you to check that an object is not a specific object (identity comparison):
result = None
# Check that the result has been defined
if result is not None:
print(f"The result is: {result}")
else:
print("No result available.")is not is preferred over not ... is for readability reasons. The PEP 8 style guide explicitly recommends writing x is not None rather than not x is None.
Operator precedence of not
It is essential to understand the precedence of not relative to other operators. Here is the order of precedence for logical operators in Python, from highest to lowest:
| Precedence | Operator | Description |
|---|---|---|
| 1 (high) | not | Logical negation |
| 2 | and | Logical AND |
| 3 (low) | or | Logical OR |
This means that not is evaluated before and, which is itself evaluated before or. Let's see an example:
a = True
b = False
c = True
# not is evaluated first
result = not a or b and c
# Equivalent to: (not a) or (b and c)
# = False or (False and True)
# = False or False
# = False
print(result) # FalseWhen in doubt, use parentheses to make your intention explicit. Clear code is always preferable to concise but ambiguous code.
Also be careful about the precedence of not relative to comparison operators:
x = 5
# not is applied AFTER the comparison
print(not x == 5) # not (x == 5) → not True → False
# This is NOT the same as
print((not x) == 5) # (not 5) == 5 → False == 5 → FalseComparison operators (==, !=, <, >, etc.) have a higher precedence than not. But not has a lower precedence than arithmetic operators. This can be a source of confusion, hence the importance of parentheses.
The double not (not not)
You may sometimes encounter the expression not not in Python code. This is a technique to explicitly convert a value to its boolean equivalent:
value = 42
print(not not value) # True
print(bool(value)) # True (more readable equivalent)
empty_value = ""
print(not not empty_value) # False
print(bool(empty_value)) # False (more readable equivalent)Although not not works, it is recommended to use the bool() function which is much more explicit and readable. The double not is considered an anti-pattern in Python.
Customizing not behavior with __bool__
When you create your own class, you can control the behavior of not by defining the special methods __bool__ or __len__:
class Inventory:
def __init__(self, items=None):
self.items = items or []
def __bool__(self):
return len(self.items) > 0
def __repr__(self):
return f"Inventory({self.items})"
# An empty inventory is falsy
empty_inventory = Inventory()
print(not empty_inventory) # True
if not empty_inventory:
print("The inventory is empty, order more stock!")
# A filled inventory is truthy
full_inventory = Inventory(["keyboard", "mouse", "monitor"])
print(not full_inventory) # False
if not full_inventory:
print("The inventory is empty.")
else:
print(f"The inventory contains {len(full_inventory.items)} items.")If the __bool__ method is not defined, Python uses __len__: an object with length 0 is falsy. If neither __bool__ nor __len__ are defined, the object is always truthy.
Best practices with the not operator
Here are the essential rules to follow for using not effectively and Pythonically:
1. Prefer idiomatic forms
# ✅ Good - Pythonic
if not my_list:
print("Empty list")
# ❌ Less good - Not Pythonic
if len(my_list) == 0:
print("Empty list")
2. Use is not and not in rather than not ... is and not ... in
# ✅ Good - Recommended by PEP 8
if x is not None:
pass
if element not in collection:
pass
# ❌ Less good - Discouraged
if not x is None:
pass
if not element in collection:
pass
3. Avoid unnecessary double negations
# ✅ Good
if condition:
pass
# ❌ Bad - Confusing double negation
if not not condition:
pass
4. Simplify expressions with not
# ✅ Good - Direct and clear
if not is_valid:
raise ValueError("Invalid data")
# ❌ Less good - Superfluous comparison
if is_valid == False:
raise ValueError("Invalid data")
# ❌ Even worse
if not is_valid == True:
raise ValueError("Invalid data")
5. Use parentheses for complex expressions
# ✅ Good - Clear thanks to parentheses
if not (age >= 18 and has_license):
print("You cannot drive.")
# ❌ Ambiguous without parentheses
if not age >= 18 and has_license:
print("Unexpected behavior possible")
De Morgan's laws with not
De Morgan's laws are an essential mathematical concept for simplifying logical expressions. They apply directly in Python:
# De Morgan's Law 1:
# not (A and B) == (not A) or (not B)
A = True
B = False
print(not (A and B)) # True
print((not A) or (not B)) # True (identical)
# De Morgan's Law 2:
# not (A or B) == (not A) and (not B)
print(not (A or B)) # False
print((not A) and (not B)) # False (identical)These laws are very useful for rewriting complex conditions in a more readable way:
# These two forms are equivalent
if not (is_admin or is_moderator):
print("Access denied")
if not is_admin and not is_moderator:
print("Access denied")Choose the form that makes your intention clearest depending on the context.
Frequently asked questions
What is the difference between not, != and is not in Python?
not is a logical negation operator that inverts a boolean value (not True gives False). != is a comparison operator that checks if two values are different (5 != 3 gives True). is not checks that two variables do not point to the same object in memory (a is not b). Each has a distinct role: not inverts, != compares values, and is not compares identities.
Why does not [] return True in Python?
In Python, an empty list ([]) is considered a falsy value, meaning it evaluates to False in a boolean context. The not operator inverts this value, which gives True. The same principle applies to all empty collections: empty dict ({}), empty tuple (()), empty set (set()), empty string (""), and the value None.
Can you use not with lambda functions in Python?
Yes, absolutely. You can use not in a lambda function just like in any Python expression. For example: is_odd = lambda n: not n % 2 == 0. This is particularly useful with functions like filter(): list(filter(lambda x: not x.startswith("_"), names)) to filter elements that don't start with an underscore.
How can I learn to master logical operators in Python?
To master not and the other logical operators in Python, regular practice is essential. Start by writing small conditions, then progressively build more complex expressions by combining not, and, and or. For a structured and comprehensive learning experience, our dedicated Python course will help you deeply understand all the operators and mechanisms of the language, with practical exercises at every step.