The not operator in Python: logical negation explained

Discover the not operator in Python: logical negation, truthy and falsy values, best practices, and concrete examples to master this boolean operator.
10 min read
Believemy logo

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:

PYTHON
not expression

The operator first evaluates the expression that follows it, then returns the inverse boolean value. Let's see this with the most basic cases:

PYTHON
print(not True)   # False
print(not False)  # True

This is the fundamental behavior: not True gives False and not False gives True. Here is the complete truth table for the not operator:

ExpressionResult
not TrueFalse
not FalseTrue

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:

Valuenot valueExplanation
NoneTrueThe absence of value
FalseTrueThe boolean false
0TrueThe integer zero
0.0TrueThe float zero
""TrueThe empty string
[]TrueThe empty list
()TrueThe empty tuple
{}TrueThe empty dict
set()TrueThe empty set

Let's verify this with a concrete example:

PYTHON
# 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:

PYTHON
print(not 42)           # False
print(not "Hello")      # False
print(not [1, 2, 3])    # False
print(not {"key": "val"})  # False

This 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:

PYTHON
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

PYTHON
user = None

if not user:
    print("No user logged in.")
    # Redirect to login page
else:
    print(f"Welcome, {user}!")
Warning

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

PYTHON
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:

PYTHON
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:

PYTHON
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.
Good to know

not in works with all iterables: list, tuple, set, dict (checks keys), strings, etc.

 

Using is not

Similarly, is not allows you to check that an object is not a specific object (identity comparison):

PYTHON
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.")
Good to know

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:

PrecedenceOperatorDescription
1 (high)notLogical negation
2andLogical AND
3 (low)orLogical OR

This means that not is evaluated before and, which is itself evaluated before or. Let's see an example:

PYTHON
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)  # False
Warning

When 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:

PYTHON
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 → False

Comparison 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:

PYTHON
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__:

PYTHON
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.")
Good to know

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

PYTHON
# ✅ 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

PYTHON
# ✅ 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

PYTHON
# ✅ Good
if condition:
    pass

# ❌ Bad - Confusing double negation
if not not condition:
    pass

 

4. Simplify expressions with not

PYTHON
# ✅ 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

PYTHON
# ✅ 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:

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:

PYTHON
# 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

Question

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.

 

Question

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.

 

Question

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.

 

Question

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.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.