Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Using the Python not Operator
Python’s not
operator allows you to invert the truth value of Boolean expressions and objects. You can use this operator in Boolean contexts, such as if
statements and while
loops. It also works in non-Boolean contexts, which allows you to invert the truth value of your variables.
Using the not
operator effectively will help you write accurate negative Boolean expressions to control the flow of execution in your programs.
In this tutorial, you’ll learn:
- How Python’s
not
operator works - How to use the
not
operator in Boolean and non-Boolean contexts - How to use the
operator.not_()
function to perform logical negation - How and when to avoid unnecessary negative logic in your code
You’ll also code a few practical examples that will allow you to better understand some of the primary use cases of the not
operator and the best practices around its use. To get the most out of this tutorial, you should have some previous knowledge about Boolean logic, conditional statements, and while
loops.
Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.
Working With Boolean Logic in Python
George Boole put together what is now known as Boolean algebra, which relies on true and false values. It also defines a set of Boolean operations: AND
, OR
, and NOT
. These Boolean values and operators are helpful in programming because they help you decide the course of action in your programs.
In Python, the Boolean type, bool
, is a subclass of int
:
>>> issubclass(bool, int)
True
>>> help(bool)
Help on class bool in module builtins:
class bool(int)
bool(x) -> bool
...
This type has two possible values, True
and False
, which are built-in constants in Python and must be capitalized. Internally, Python implements them as integer numbers:
>>> type(True)
<class 'bool'>
>>> type(False)
<class 'bool'>
>>> isinstance(True, int)
True
>>> isinstance(False, int)
True
>>> int(True)
1
>>> int(False)
0
Python internally implements its Boolean values as 1
for True
and 0
for False
. Go ahead and execute True + True
in your interactive shell to see what happens.
Python provides three Boolean or logical operators:
With these operators, you can build expressions by connecting Boolean expressions with each other, objects with each other, and even Boolean expressions with objects. Python uses English words for the Boolean operators. These words are keywords of the language, so you can’t use them as identifiers without causing a syntax error.
In this tutorial, you’ll learn about Python’s not
operator, which implements the logical NOT
operation or negation.
Getting Started With Python’s not
Operator
The not
operator is the Boolean or logical operator that implements negation in Python. It’s unary, which means that it takes only one operand. The operand can be a Boolean expression or any Python object. Even user-defined objects work. The task of not
is to reverse the truth value of its operand.
If you apply not
to an operand that evaluates to True
, then you get False
as a result. If you apply not
to a false operand, then you get True
:
>>> not True
False
>>> not False
True
The not
operator negates the truth value of its operand. A true operand returns False
. A false operand returns True
. These two statements uncover what is commonly known as the truth table of not
:
operand |
not operand |
---|---|
True |
False |
False |
True |
With not
, you can negate the truth value of any Boolean expression or object. This functionality makes it worthwhile in several situations:
- Checking unmet conditions in the context of
if
statements andwhile
loops - Inverting the truth value of an object or expression
- Checking if a value is not in a given container
- Checking for an object’s identity
In this tutorial, you’ll find examples that cover all these use cases. To kick things off, you’ll start by learning how the not
operator works with Boolean expressions and also with common Python objects.
A Boolean expression always returns a Boolean value. In Python, this kind of expression returns True
or False
. Say you want to check if a given numeric variable is greater than another:
>>> x = 2
>>> y = 5
>>> x > y
False
>>> not x > y
True
The expression x > y
always returns False
, so you can say it’s a Boolean expression. If you place not
before this expression, then you get the inverse result, True
.
Note: Python evaluates operators according to a strict order, commonly known as operator precedence.
For example, Python evaluates math and comparison operators first. Then it evaluates logical operators, including not
:
>>> not True == False
True
>>> False == not True
File "<stdin>", line 1
False == not True
^
SyntaxError: invalid syntax
>>> False == (not True)
True
In the first example, Python evaluates the expression True == False
and then negates the result by evaluating not
.
In the second example, Python evaluates the equality operator (==
) first and raises a SyntaxError
because there’s no way to compare False
and not
. You can surround the expression not True
with parentheses (()
) to fix this problem. This quick update tells Python to evaluate the parenthesized expression first.
Among logical operators, not
has higher precedence than the and
operator and the or
operator, which have the same precedence.
You can also use not
with common Python objects, such as numbers, strings, lists, tuples, dictionaries, sets, user-defined objects, and so on:
>>> # Use "not" with numeric values
>>> not 0
True
>>> not 42
False
>>> not 0.0
True
>>> not 42.0
False
>>> not complex(0, 0)
True
>>> not complex(42, 1)
False
>>> # Use "not" with strings
>>> not ""
True
>>> not "Hello"
False
>>> # Use "not" with other data types
>>> not []
True
>>> not [1, 2, 3]
False
>>> not {}
True
>>> not {"one": 1, "two": 2}
False
In each example, not
negates the truth value of its operand. To determine whether a given object is truthy or falsy, Python uses bool()
, which returns True
or False
depending on the truth value of the object at hand.
This built-in function internally uses the following rules to figure out the truth value of its input:
By default, an object is considered true unless its class defines either a
__bool__()
method that returnsFalse
or a__len__()
method that returns zero, when called with the object. Here are most of the built-in objects considered false:
- constants defined to be false:
None
andFalse
.- zero of any numeric type:
0
,0.0
,0j
,Decimal(0)
,Fraction(0, 1)
- empty sequences and collections:
''
,()
,[]
,{}
,set()
,range(0)
(Source)
Once not
knows the truth value of its operand, it returns the opposite Boolean value. If the object evaluates to True
, then not
returns False
. Otherwise, it returns True
.
Note: Always returning True
or False
is an important difference between not
and the other two Boolean operators, the and
operator and the or
operator.
The and
operator and the or
operator return one of the operands in an expression, while the not
operator always returns a Boolean value:
>>> 0 and 42
0
>>> True and False
False
>>> True and 42 > 27
True
>>> 0 or 42
42
>>> True or False
True
>>> False or 42 < 27
False
>>> not 0
True
>>> not 42
False
>>> not True
False
With the and
operator and the or
operator, you get True
or False
back from the expression when one of these values explicitly results from evaluating the operands. Otherwise, you get one of the operands in the expression. On the other hand, not
behaves differently, returning True
or False
regardless of the operand it takes.
To behave like the and
operator and the or
operator, the not
operator would have to create and return new objects, which is often ambiguous and not always straightforward. For example, what if an expression like not "Hello"
returned an empty string (""
)? What would an expression like not ""
return? That’s the reason why the not
operator always returns True
or False
.
Now that you know how not
works in Python, you can dive into more specific use cases of this logical operator. In the following section, you’ll learn about using not
in Boolean contexts.
Using the not
Operator in Boolean Contexts
Like the other two logical operators, the not
operator is especially useful in Boolean contexts. In Python, you have two statements that define Boolean contexts:
if
statements let you perform conditional execution and take different courses of action based on some initial conditions.while
loops let you perform conditional iteration and run repetitive tasks while a given condition is true.
These two structures are part of what you’d call control flow statements. They help you decide a program’s execution path. In the case of the not
operator, you can use it to select the actions to take when a given condition is not met.
if
Statements
You can use the not
operator in an if
statement to check if a given condition is not met. To make an if
statement test if something didn’t happen, you can put the not
operator in front of the condition at hand. Since the not
operator returns the negated result, something true becomes False
and the other way around.
The syntax for an if
statement with the not
logical operator is:
if not condition:
# Do something...
In this example, condition
could be a Boolean expression or any Python object that makes sense. For example, condition
can be a variable containing a string, a list, a dictionary, a set, and even a user-defined object.
If condition
evaluates to false, then not
returns True
and the if
code block runs. If condition
evaluates to true, then not
returns False
and the if
code block doesn’t execute.
A common situation is one where you use a predicate or Boolean-valued function as a condition
. Say you want to check if a given number is prime before doing any further processing. In that case, you can write an is_prime()
function:
>>> import math
>>> def is_prime(n):
... if n <= 1:
... return False
... for i in range(2, int(math.sqrt(n)) + 1):
... if n % i == 0:
... return False
... return True
...
>>> # Work with prime numbers only
>>> number = 3
>>> if is_prime(number):
... print(f"{number} is prime")
...
3 is prime
In this example, is_prime()
takes an integer number as an argument and returns True
if the number is prime. Otherwise, it returns False
.
You can also use this function in a negative conditional statement to approach those situations where you want to work with composite numbers only:
>>> # Work with composite numbers only
>>> number = 8
>>> if not is_prime(number):
... print(f"{number} is composite")
...
8 is composite
Since it’s also possible that you need to work with composite numbers only, you can reuse is_prime()
by combining it with the not
operator as you did in this second example.
Another common situation in programming is to find out if a number is inside a specific numeric interval. To determine if a number x
is in a given interval in Python, you can use the and
operator or you can chain comparison operators appropriately:
>>> x = 30
>>> # Use the "and" operator
>>> if x >= 20 and x < 40:
... print(f"{x} is inside")
...
30 is inside
>>> # Chain comparison operators
>>> if 20 <= x < 40:
... print(f"{x} is inside")
...
30 is inside
In the first example, you use the and
operator to create a compound Boolean expression that checks if x
is between 20
and 40
. The second example makes the same check but using chained operators, which is a best practice in Python.
Note: In most programming languages, the expression 20 <= x < 40
doesn’t make sense. It would start by evaluating 20 <= x
, which is true. The next step would be to compare that true result with 40
, which doesn’t make much sense, so the expression fails. In Python, something different happens.
Python internally rewrites this type of expression to an equivalent and
expression, such as x >= 20 and x < 40
. It then performs the actual evaluation. That’s why you get the correct result in the example above.
You may also face the need to check if a number is outside of the target interval. To this end, you can use the or
operator:
>>> x = 50
>>> if x < 20 or x >= 40:
... print(f"{x} is outside")
...
50 is outside
This or
expression allows you to check if x
is outside the 20
to 40
interval. However, if you already have a working expression that successfully checks if a number is in a given interval, then you can reuse that expression to check the opposite condition:
>>> x = 50
>>> # Reuse the chained logic
>>> if not (20 <= x < 40):
... print(f"{x} is outside")
50 is outside
In this example, you reuse the expression you originally coded to determine if a number is inside a target interval. With not
before the expression, you check if x
is outside the 20
to 40
interval.
while
Loops
The second Boolean context in which you can use the not
operator is in your while
loops. These loops iterate while a given condition is met or until you jump out of the loop by using break
, using return
, or raising an exception. Using not
in a while
loop allows you to iterate while a given condition is not met.
Say you want to code a small Python game to guess a random number between 1 and 10. As a first step, you decide to use input()
to capture the user’s name. Since the name is a requirement for the rest of the game to work, you need to make sure you get it. To do that, you can use a while
loop that asks for the user’s name until the user provides a valid one.
Fire up your code editor or IDE and create a new guess.py
file for your game. Then add the following code:
1# guess.py
2
3from random import randint
4
5secret = randint(1, 10)
6
7print("Welcome!")
8
9name = ""
10while not name:
11 name = input("Enter your name: ").strip()
In guess.py
, you first import randint()
from random
. This function allows you to generate random integer numbers in a given range. In this case, you’re generating numbers from 1
to 10
, both included. Then you print a welcoming message to the user.
The while
loop on line 10 iterates until the user provides a valid name. If the user provides no name by just pressing Enter, then input()
returns an empty string (""
) and the loop runs again because not ""
returns True
.
Now you can continue with your game by writing the code to provide the guessing functionality. You can do it by yourself, or you can expand the box below to check out a possible implementation.
The second part of the game should allow the user to enter a number from 1 to 10 as their guess. The game should compare the user’s input with the current secret number and take actions accordingly. Here’s a possible implementation:
while True:
user_input = input("Guess a number between 1 and 10: ")
if not user_input.isdigit():
user_input = input("Please enter a valid number: ")
guess = int(user_input)
if guess == secret:
print(f"Congrats {name}! You win!")
break
elif guess > secret:
print("The secret number is lower than that...")
else:
print("The secret number is greater than that...")
You use an infinite while
loop to take the user’s input until they guess the secret
number. In every iteration, you check if the input matches secret
and provide clues to the user according to the result. Go ahead and give it a try!
As an exercise, you can restrict the number of attempts before the user loses the game. Three attempts could be a nice option in this case.
How was your experience with this little game? To learn more about game programming in Python, check out PyGame: A Primer on Game Programming in Python.
Now that you know how to use not
in Boolean contexts, it’s time to learn about using not
in non-Boolean contexts. That’s what you’ll do in the following section.
Using the not
Operator in Non-Boolean Contexts
Since the not
operator can also take regular objects as an operand, you can use it in non-Boolean contexts too. In other words, you can use it outside of an if
statement or a while
loop. Arguably, the most common use case of the not
operator in a non-Boolean context is to invert the truth value of a given variable.
Suppose you need to perform two different actions alternatively in a loop. In that case, you can use a flag variable to toggle actions in every iteration:
>>> toggle = False
>>> for _ in range(4):
... print(f"toggle is {toggle}")
... if toggle:
... # Do something...
... toggle = False
... else:
... # Do something else...
... toggle = True
...
toggle is False
toggle is True
toggle is False
toggle is True
Every time this loop runs, you check the truth value of toggle
to decide which course of action to take. At the end of each code block, you change the value of toggle
so you can run the alternative action in the next iteration. Changing the value of toggle
requires you to repeat a similar logic twice, which might be error-prone.
You can use the not
operator to overcome this drawback and make your code cleaner and safer:
>>> toggle = False
>>> for _ in range(4):
... print(f"toggle is {toggle}")
... if toggle:
... pass # Do something...
... else:
... pass # Do something else...
... toggle = not toggle
...
toggle is False
toggle is True
toggle is False
toggle is True
Now the highlighted line alternates the value of toggle
between True
and False
using the not
operator. This code is cleaner, less repetitive, and less error-prone than the example you wrote before.
Using the Function-Based not
Operator
Unlike the and
operator and the or
operator, the not
operator has an equivalent function-based implementation in the operator
module. The function is called not_()
. It takes an object as an argument and returns the same outcome as an equivalent not obj
expression:
>>> from operator import not_
>>> # Use not_() with numeric values
>>> not_(0)
True
>>> not_(42)
False
>>> not_(0.0)
True
>>> not_(42.0)
False
>>> not_(complex(0, 0))
True
>>> not_(complex(42, 1))
False
>>> # Use not_() with strings
>>> not_("")
True
>>> not_("Hello")
False
>>> # Use not_() with other data types
>>> not_([])
True
>>> not_([1, 2, 3])
False
>>> not_({})
True
>>> not_({"one": 1, "two": 2})
False
To use not_()
, you first need to import it from operator
. Then you can use the function with any Python object or expression as an argument. The result is the same as using an equivalent not
expression.
Note: Python also has and_()
and or_()
functions. However, they reflect their corresponding bitwise operators rather than the Boolean ones.
The and_()
and or_()
functions also work with Boolean arguments:
>>> from operator import and_, or_
>>> and_(False, False)
False
>>> and_(False, True)
False
>>> and_(True, False)
False
>>> and_(True, True)
True
>>> or_(False, False)
False
>>> or_(False, True)
True
>>> or_(True, False)
True
>>> or_(True, True)
True
In these examples, you use and_()
and or_()
with True
and False
as arguments. Note that the result of the expressions matches the truth table of the and
and not
operators, respectively.
Using the not_()
function instead of the not
operator is handy when you’re working with higher-order functions, such as map()
, filter()
, and the like. Here’s an example that uses the not_()
function along with sorted()
to sort a list of employees by placing empty employee names at the end of the list:
>>> from operator import not_
>>> employees = ["John", "", "", "Jane", "Bob", "", "Linda", ""]
>>> sorted(employees, key=not_)
['John', 'Jane', 'Bob', 'Linda', '', '', '', '']
In this example, you have an initial list called employees
that holds a bunch of names. Some of those names are empty strings. The call to sorted()
uses not_()
as a key
function to create a new list that sorts the employees, moving the empty names to the end of the list.
Working With Python’s not
Operator: Best Practices
When you’re working with the not
operator, you should consider following a few best practices that can make your code more readable, clean, and Pythonic. In this section, you’ll learn about some of these best practices related to using the not
operator in the context of membership and identity tests.
You’ll also learn how negative logic can impact the readability of your code. Finally, you’ll learn about some handy techniques that can help you avoid unnecessary negative logic, which is a programming best practice.
Test for Membership
Membership tests are commonly useful when you’re determining if a particular object exists in a given container data type, such as a list, tuple, set, or dictionary. To perform this kind of test in Python, you can use the in
operator:
>>> numbers = [1, 2, 3, 4]
>>> 3 in numbers
True
>>> 5 in numbers
False
The in
operator returns True
if the left-side object is in the container on the right side of the expression. Otherwise, it returns False
.
Sometimes you may need to check if an object is not in a given container. How can you do that? The answer to this question is the not
operator.
There are two different syntaxes to check if an object is not in a given container in Python. The Python community considers the first syntax as bad practice because it’s difficult to read. The second syntax reads like plain English:
>>> # Bad practice
>>> not "c" in ["a", "b", "c"]
False
>>> # Best practice
>>> "c" not in ["a", "b", "c"]
False
The first example works. However, the leading not
makes it difficult for someone reading your code to determine if the operator is working on "c"
or on the whole expression, "c" in ["a", "b", "c"]
. This detail makes the expression difficult to read and understand.
The second example is much clearer. The Python documentation refers to the syntax in the second example as the not in
operator. The first syntax can be a common practice for people who are starting out with Python.
Now it’s time to revisit the examples where you checked if a number was inside or outside a numeric interval. If you’re working with integer numbers only, then the not in
operator provides a more readable way to perform this check:
>>> x = 30
>>> # Between 20 and 40
>>> x in range(20, 41)
True
>>> # Outside 20 and 40
>>> x not in range(20, 41)
False
The first example checks if x
is inside the 20
to 40
range or interval. Note that you use 41
as the second argument to range()
to include 40
in the check.
Note: Did you know that membership tests with range()
are very efficient? Learn more in Why Are Membership Tests So Fast for range()
in Python?.
When you’re working with integer numbers, this small trick about where exactly you use the not
operator can make a big difference regarding code readability.
Check the Identity of Objects
Another common requirement when you’re coding in Python is to check for an object’s identity. You can determine an object’s identity using id()
. This built-in function takes an object as an argument and returns an integer number that uniquely identifies the object at hand. This number represents the object’s identity.
The practical way to check for identity is to use the is
operator, which is pretty useful in some conditional statements. For example, one of the most common use cases of the is
operator is to test if a given object is None
:
>>> obj = None
>>> obj is None
True
The is
operator returns True
when the left operand has the same identity as the right operand. Otherwise, it returns False
.
In this case, the question is: how do you check if two objects don’t have the same identity? Again, you can use two different syntaxes:
>>> obj = None
>>> # Bad practice
>>> not obj is None
False
>>> # Best practice
>>> obj is not None
False
In both examples, you check if obj
has the same identity as the None
object. The first syntax is somewhat difficult to read and non-Pythonic. The is not
syntax is way more explicit and clear. The Python documentation refers to this syntax as the is not
operator and promotes its use as a best practice.
Avoid Unnecessary Negative Logic
The not
operator enables you to reverse the meaning or logic of a given condition or object. In programming, this kind of feature is known as negative logic or negation.
Using negative logic correctly can be tricky because this logic is difficult to think about and understand, not to mention hard to explain. In general, negative logic implies a higher cognitive load than positive logic. So, whenever possible, you should use positive formulations.
Here is an example of a custom_abs()
function that uses a negative condition to return the absolute value of an input number:
>>> def custom_abs(number):
... if not number < 0:
... return number
... return -number
...
>>> custom_abs(42)
42
>>> custom_abs(-42)
42
This function takes a number as an argument and returns its absolute value. You can achieve the same result by using positive logic with a minimal change:
>>> def custom_abs(number):
... if number < 0:
... return -number
... return number
...
>>> custom_abs(42)
42
>>> custom_abs(-42)
42
That’s it! Your custom_abs()
now uses positive logic. It’s more straightforward and understandable. To get this result, you removed not
and moved the negative sign (-
) to modify the input number
when it’s lower than 0
.
Note: Python provides a built-in function called abs()
that returns the absolute value of a numeric input. The purpose of custom_abs()
is to facilitate the topic presentation.
You can find many similar examples in which changing a comparison operator can remove unnecessary negative logic. Say you want to check if a variable x
is not equal to a given value. You can use two different approaches:
>>> x = 27
>>> # Use negative logic
>>> if not x == 42:
... print("not 42")
...
not 42
>>> # Use positive logic
>>> if x != 42:
... print("not 42")
...
not 42
In this example, you remove the not
operator by changing the comparison operator from equal (==
) to different (!=
). In many cases, you can avoid negative logic by expressing the condition differently with an appropriate relational or equality operator.
However, sometimes negative logic can save you time and make your code more concise. Suppose you need a conditional statement to initialize a given file when it doesn’t exist in the file system. In that case, you can use not
to check if the file doesn’t exist:
from pathlib import Path
file = Path("/some/path/config.ini")
if not file.exists():
# Initialize the file here...
The not
operator allows you to invert the result of calling .exists()
on file
. If .exists()
returns False
, then you need to initialize the file. However, with a false condition, the if
code block doesn’t run. That’s why you need the not
operator to invert the result of .exists()
.
Note: The example above uses pathlib
from the standard library to handle file paths. To dive deeper into this cool library, check out Python 3’s pathlib Module: Taming the File System.
Now think of how to turn this negative conditional into a positive one. Up to this point, you don’t have any action to perform if the file exists, so you may think of using a pass
statement and an additional else
clause to handle the file initialization:
if file.exists():
pass # YAGNI
else:
# Initialize the file here...
Even though this code works, it violates the “You aren’t gonna need it” (YAGNI) principle. It’s an especially determined attempt to remove negative logic.
The idea behind this example is to show that sometimes using negative logic is the right way to go. So, you should consider your specific problem and select the appropriate solution. A good rule of thumb would be to avoid negative logic as much as possible without trying to avoid it at all costs.
Finally, you should pay special attention to avoiding double negation. Say you have a constant called NON_NUMERIC
that holds characters that Python can’t turn into numbers, such as letters and punctuation marks. Semantically, this constant itself implies a negation.
Now say you need to check if a given character is a numeric value. Since you already have NON_NUMERIC
, you can think of using not
to check the condition:
if char not in NON_NUMERIC:
number = float(char)
# Do further computations...
This code looks odd, and you probably won’t ever do something like this in your career as a programmer. However, doing something similar can sometimes be tempting, such as in the example above.
This example uses double negation. It relies on NON_NUMERIC
and also on not
, which makes it hard to digest and understand. If you ever get to a piece of code like this, then take a minute to try writing it positively or, at least, try to remove one layer of negation.
Conclusion
Python’s not
is a logical operator that inverts the truth value of Boolean expressions and objects. It’s handy when you need to check for unmet conditions in conditional statements and while
loops.
You can use the not
operator to help you decide the course of action in your program. You can also use it to invert the value of Boolean variables in your code.
In this tutorial, you learned how to:
- Work with Python’s
not
operator - Use the
not
operator in Boolean and non-Boolean contexts - Use
operator.not_()
to perform logical negation in a functional style - Avoid unnecessary negative logic in your code whenever possible
To these ends, you coded a few practical examples that helped you understand some of the main use cases of the not
operator, so you’re now better prepared to use it in your own code.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Using the Python not Operator