Select Page

Operators in Python: What Happens Behind the Scene

In this tutorial, you’ll learn about all the operators in Python. Instead of just learning their basic usage, what you might already know, you’ll achieve a broader understanding of how they behave behind the scene and what’s possible to do with them.

As of Python 3.9, operators in Python can be divided into the following categories:

  1. Power Operator: **
  2. Unary Arithmetic: , +, ~
  3. Binary Arithmetic: *, @, /, //, %, +,
  4. Shifting Operators: <<, >>
  5. Binary Bitwise Operators: &, ^, |
  6. Comparisions:
    1. Value Comparisons: <, >, ==, >=, <=, !=
    2. Membership Test: in, not in
    3. Identity Comparisons: is, is not
  7. Boolean Operators: or, and, not
  8. Walrus Operator: :=
  9. Augmented Assignment Operators

Notice that the categories have been arranged according to their precedence. The precedence of the operators decreases from top to bottom but increases from left to right in the same category. Except for the Binary Arithmetic where the +, – operators have less priority than the rest of the same category.

Operators Precedence Documentation

Before we get started, let’s see some useful definitions.

What are Operators?

An Operator is a special symbol that indicates to a specific operation or computation. For example, the plus symbol (+) indicates to the addition operation.

What is an Operand?

An Operand is a data on which an operator operates. Some operator require one operand whereas some require two. For example, x + y. Here x and y are two operands.

What is an Expression?

An Expression is a combination of some Operators and Operands that evaluates to a single value. For example, 5 + 3 is an expression, and evaluates to 8.

Now let’s dive into each of the operators. If you’ve already read the previous tutorial on Python Numbers, Formatting Number, and math Module: A Complete Guide, where I’ve already covered two types of operators, don’t worry! This tutorial will add some extra spice on top of that. So let’s get started!

Power Operator: **

The syntax of the power operator is a**b, which returns ab. The power operator is more powerful than the unary operators (known as the sign of a number) on the left. That means, -1**2 evaluates to -(12), and not (-1)2 as you may expect.

Operators in Python generally evaluate from left to right. But the power operator evaluates from right to left. For example, 2**3**4 equals to 2**(3**4), what we actually do in math.

Here are some examples:

>>> 3**2
9
>>> -1**2
-1
>>> -(1**2)
-1
>>> 2**3**4
2417851639229258349412352
>>> (2**3)**4
4096
>>> 2**(3**4)
2417851639229258349412352
>>> 2**-2
0.25

The power operator works the same as the built-in pow( ) function, when called with 2 arguments. That means, pow(2,3) == 2**3 == 23

The numeric arguments of the power operator are first converted into a common type, and the result is returned in the same type. It turns out that if at least one argument is a float, then all are converted into floats. And if at least one argument is a complex, then all are converted into complexes.

An alternate happens when both arguments are ints, but the second one is a negative number. In that case, all are converted into floats and the returned value is also in float.

how power operator works

Raising 0.0 to a negative number results in a ZeroDivisionError. Raising a negative number to a fractional number results in a complex number. Both of these are common in mathematics.

>>> -10**0.5    # The power operator has higher precedence than unary sign
-3.1622776601683795
>>> (-10)**0.5
(1.9363366072701937e-16+3.1622776601683795j)

Unary Arithmetic and Bitwise Operation: -, +, ~

  • The unary minus () operator represents the negation of a number. For example, -5, -10
  • The unary plus ( + ) operator yields its numeric argument unchanged. It’s generally not used. Example: +5, +10. Generally, you’ll always use 5, 10 instead.
  • The unary invert ( ~ ) operator calculates the bitwise inversion of its integer argument. The bitwise inversion of a number X is defined as -(X+1). Note that the argument X must be an integer number.
>>> ~0     # -(0+1)
-1
>>> ~1     # -(1+1)
-2
>>> ~2     # -(2+1)
-3
>>> ~-1    # -(-1+1)
0
>>> ~-2    # -(-2+1)
1

All unary arithmetics have the same priority. But when represented together, the priority increases from left to right. That means, “-“ < “+” < “~”

>>> 2+-2    # (2)+(-2)
0
>>> -2+-2   # (-2)+(-2)
-4

The plus sign between two arguments is not a unary plus operator. That’s a binary plus operator, which adds two numbers.

Binary Arithmetic Operations: *, @, /, //, %, +, –

The operators in Python that perform arithmetic operations on two arguments are called Binary Arithmetic Operators. They have the conventional priority level. When used together, priority increases from left to right.

The multiplication ( * ) and the addition ( + ) operators work not only with numbers, but also with sequence types.

Multiplication Operator: “*”

The multiplication ( * ) operator returns the product of its arguments. Depending on the type of the arguments, the operations can differ.

  • When both the arguments are numbers: Both arguments are first converted into a common type, and then multiplied together.
  • When one argument is an integer, the other one is a sequence: The sequence repetition happens. If the integer is a negative number, an empty sequence is returned.

The conversion of common types of numbers is always the same. If at least one is a complex, then all are converted into complex numbers. If at least one is a float, then all are converted into floats. The priority being complex > float > int

Example 1:

>>> 123 * 321
39483
>>> 123 * 32.19
3959.37
>>> 123 * (3+2j)
(369+246j)
>>> 12.3 * 3 * 2j
73.80000000000001j

Example 2:

>>> 'abc' * 2
'abcabc'
>>> 2 * 'abc'
'abcabc'
>>> 2 * 'abc' * 2
'abcabcabcabc'
>>> [1,2,3] * 2
[1, 2, 3, 1, 2, 3]
>>> b'abc' * 2    # byte string
b'abcabc'

Matrix Multiplication Operator: “@”

The at (@) operator is used to perform matrix multiplication. But no built-in type has support for this operator, as no built-in type works with matrix multiplication. The third-party or external numeric libraries can have support for this. For example, the NumPy module deals with matrix multiplication. Hence, the NumPy module supports the at operator.

The numpy module comes by default with the anaconda distribution.

operators in python include matrix multiplication operator. But no built-in type has support for it

Division Operator: “/”

The division operator returns the quotient of their arguments. In the syntax a/b, a is divided by b. The arguments are first converted into a common type and then the operator is applied. But the division of two integers is always a float, even there is no decimal point. Note that if b==0, then a ZeroDivisionError is raised. You’ll see people calling the division operator as float division operator, but it can also return the result in a complex number!

>>> 10/2
5.0
>>> 10/2.5
4.0
>>> 10.6/2.3
4.608695652173913
>>> (2+3j)/(4+5j)
(0.5609756097560976+0.0487804878048781j)

Floor Division Operator: “//”

The floor division operator (//) is kind of a combination of the division operator and the floor function. It first divides the number, and then rounds down the result. As always, the arguments are converted to a common type, and then the operator is applied. Note that, Python floor division operator does not support complex numbers. Remember, it’s floor division and not integer division like many websites name it!

>>> 10//2
5
>>> 10//2.0
5.0
>>> 10//2.5
4.0
>>> 10.6//2.3
4.0
>>> (2+3j)//(4+5j)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
>>> 10//(2+3j)

Floor division of negative numbers

The floor division can be confusing if applied on negative numbers. For example:

>>> 9//2
4
>>> -9//2
-5

Notice that the behavior is as expected. Because, -9/2 = -4.5. Now rounding it to -4 would be rounding it up, and not down. Because -4 > -4.5.

Modulo Operator: “%”

The modulo operator returns the remainder of a division operation. The syntax is a%b. If b==0, a ZeroDivisionError is raised. Both of the numeric arguments are first converted into a common type and then the operator is applied.

>>> 10%3
1
>>> 3.14%0.7
0.3400000000000003

It’s not exactly 0.34 because of Floating Point Arithmetic: Issues and Limitations.

The modulo operator always returns the result with the same sign as the second argument. That means, if the second argument is a negative number, the modulo operator must return a negative remainder.

>>> -10%3
2
>>> 10%-3
-2
>>> -10%-3
-1

Let me explain the second one about how it works.

>>> 10%-3
-2
>>> 10//-3
-4
>>> (-3*-4)+(-2)
10

If you’re working with the decimal module, be conscious about the fact that it takes the ceil in the floor division (//) (instead of floor) and yields a result with the same sign as its first operand (instead of the second) in modulo operation.

For more: Modulo operation on a python negative decimal.Decimal and a positive int

Both the floor division and the modulo operation are not applicable to complex numbers. But if you need, first convert the complex number into its absolute value using the abs( ) function.

Binary Addition Operator: “+”

When a plus sign (+) is used between two operands, it performs Binary Addition. It yields the summation of the arguments. The binary addition power has less priority than the unary plus and minus operators.

  • Both arguments can be numbers. In this case, both the arguments are first converted into a common type and then added together.
>>> 2+2
4
>>> 2+-2   # (+2)+(-2) as unary operator has higher priority
0
>>> -2+-2
-4
  • Both the arguments can be any sequence type. In this case, the sequences are added together.
>>> 'Hello ' + 'World!'
'Hello World!'
>>> [1,2,3] + [4,5,6]
[1, 2, 3, 4, 5, 6]
>>> b'abc' + b'def'
b'abcdef'
  • A combination of number and sequence type, or different types is not allowed.
>>> 'MLwiki' + 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
>>> [2,3,4] + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> 'MLwiki' + [2,3,4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "list") to str

Binary Subtraction Operator: “-“

When a minus sign (+) is used between two operands, it performs Binary subtraction. It yields the difference between the arguments. The binary subtraction power has less priority than the unary plus and minus operators.

The arguments of the binary subtraction operator ( ) must always be numbers. The arguments are first converted into a common type.

>>> 2-2
0
>>> 2--2
4
>>> -2+-2    # No binary subtraction operator here
-4
Join Facebook Group

Public Group

A group optimized for learning purposes. Track your progress by joining a unit

Follow on Quora

Public Space

Best place to ask questions! Join the built-in community to get help from others

Shifting Operations: <<, >>

Shifting operations are applicable to binary numbers. As numbers are stored in binary format, you can apply shifting operations on any number base. But only integers (Binary, Octal, Decimal, and Hexadecimal) are supported.

Shifting are of 2 types: right shift and left shift. Binary numbers are stored in memory as bytes. 1 byte equals 8 bits. One bit contains either 0 or 1. Say, the number 42 is stored in a 1-byte memory. It would look like this:

binary number representation in memory

Right shifting it by 2 bits means shifting the entire number to the right by 2 bits. In this case, the rightmost 2 bits will get dropped as you can’t add new bits to the right. Because that will change the base values for the entire representation.

right shifting a number by 2 bits

Left shifting by 2 bits means shifting the entire number to the left by 2 bits. Note that in both cases, empty bits are filled with zeros.

left shifting a number by 2 bits

Operators in Python includes right shift and left shift operations. The syntax is as follows:

Right Shift:    number >> bits
Left Shift:     number << bits

Shifting can be defined as a power of 2. So right shifting x by n bits means x // 2n or x // pow(2,n), whereas left shifting means x * 2n or x * pow(2,n).

>>> 42>>2
10
>>> 42//pow(2,2)
10
>>> 
>>> 42<<2
168
>>> 42*pow(2,2)
168
>>> 
>>> 0b101100101 >> 3
44
>>> 0b101100101 << 10
365568

Binary Bitwise Operations: &, ^, |

Binary bitwise operations include bitwise AND (&), bitwise X-OR (^), and bitwise OR (|). Their priority increases from left to right. All three of the operations only support integer numbers. Bitwise operations are generally used to create complex logic gates in circuits. The numbers are first converted into binary format and then the operators are applied. Bitwise operations are applied to two identical bits at once.

Bitwise AND: “&”

The bitwise AND operation returns 1 if both the arguments are 1, otherwise returns 0.

Here is the truth table for binary bitwise AND operations:

Argument 1Argument 2Result
000
010
100
111

Here are some examples:

>>> 0&0
0
>>> 0&1
0
>>> 1&0
0
>>> 1&1
1

When the binary bitwise operation is applied on two integer numbers, they are first converted into binary numbers of 8 bits or 16 bits or anything else depending on the program. Then the bitwise operation is applied on each pair of identical bits. Finally, the resultant is converted back into a decimal by default. Here’s how it works. Let’s say the numbers are converted into 8 bits of binary.

demonstrating the binary bitwise operation

In Python:

>>> bin(13)
'0b1101'
>>> bin(31)
'0b11111'
>>> 13&31
13
>>> format(13&31, 'b')
'1101'
>>> int('1101', base=2)
13

You can compute multiple bitwise AND operations at once. Just keep in mind, they are computed from left to right. For example, 13&31&131 equals ((13&31) & 131).

>>> 13&31&131
1
>>> 13&31
13
>>> 13&131    # This 13 is the previous result
1
>>> ((13&31)&131)
1

Bitwise X-OR (Exclusive OR): “^”

Bitwise X-OR operation returns 0 if both the arguments are identical (either both 1 or both 0), otherwise 1.

Here is the truth table for binary bitwise X-OR operations:

Argument 1Argument 2Result
000
011
101
110

Here are the examples:

>>> 0^0
0
>>> 0^1
1
>>> 1^0
1
>>> 1^1
0

The binary bitwise X-OR operations are computed the same way as before. So let’s jump to the examples.

demonstrating the binary bitwise X-OR operation

In Python:

>>> bin(13)
'0b1101'
>>> bin(31)
'0b11111'
>>> 13^31
18
>>> format(13^31, 'b')
'10010'
>>> int('10010', base=2)
18

Computing multiple X-OR operations at once is the same as before. For example, 13^31^131 equals ((13^31) ^ 131).

>>> 13^31^131
145
>>> 13^31
18
>>> 18^131
145
>>> ((13^31)^(131))
145

Bitwise OR: “|”

The Bitwise OR operation returns 1 if any of the arguments is 1, otherwise returns 0.

Here is the truth table for binary bitwise OR operations:

Argument 1Argument 2Result
000
011
101
111

Here are the examples:

>>> 0|0
0
>>> 0|1
1
>>> 1|0
1
>>> 1|1
1

The binary bitwise OR operations are computed the same way as before. So let’s jump to the examples.

demonstrating binary bitwise or operation

In Python:

>>> bin(13)
'0b1101'
>>> bin(31)
'0b11111'
>>> 13|31
31
>>> format(13|31, 'b')
'11111'
>>> int('11111', base=2)
31

Computing multiple OR operations at once is the same as before. For example, 13|31|131 equals ((13|31) | 131).

>>> 13|31|131
159
>>> 13|31
31
>>> 31|131
159
>>> ((13|31)|131)
159

All Bitwise Operators at Once

When all of the three bitwise operators are used at once, the operations follow the priority: & > ^ > |

Notice the examples carefully:

>>> 13&31^131|313    # Equals ((13&31)^131)|313
447
>>> 13&31
13
>>> 13^131
142
>>> 142|313
447
>>> 
>>> 13^31|131&313|113    # Equals (13^31)|(131&313)|113
115
>>> (131&313)
1
>>> 13^31
18
>>> 18|1|113
115

Comparison Operators

The comparison operators in Python compares the first argument with respect to the second one and returns either True or False. Expressions like a < b < c have the same interpretation that is conventional in Mathematics. That means, comparisons can be chained arbitrarily. For example, the expression x < y <= z is equivalent to the expression x < y and y <= z, except that the former expression evaluates y only once while the latter evaluates twice. But in both cases, the latter part (y<=z) won’t be evaluated if x < y returns False. Because that becomes unnecessary. This behavior is known as the short circuit evaluation.

Comparison operators in Python can be categorized in 3 different sections.

Value Comparisons: <, >, ==, >=, <=, !=

The value comparison operators (<, >, ==, >=, <=, !=) compare the values of two objects. The objects do not need to have the same type.

OperatorNameExample
<Less thanx<y
>Greater thanx>y
==Equalx==y
>=Greater than or equalx>=y
<=Less than or equalx<=y
!=not equalx!=y
>>> 123<321
True
>>> 123>321
False
>>> 0==0.0
True
>>> 123>=123
True
>>> 321<=123
False
>>> 123!=321
True

To get a deeper understanding, value comparison operators in Python can be further categorized:

  1. Order Comparison: <, >, >=,<=
  2. Equality Comparison: ==, !=

Let’s describe the comparison behavior of the most important built-in types.

  • Numbers of built-in types (Numeric Types: int, float, complex) and of standard library types fractions.Fraction and decimal.Decimal can be compared within and across their types. One exception is that the complex numbers do not support Order Comparison.
>>> 12.34>=12
True
>>> 123!=0.34
True
>>> 2+3j < 3+4j
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'complex' and 'complex'
  • The not-a-number values e.g. float(‘NaN’), or decimal.Decimal(‘NaN’) are special. Any ordered comparison of a number to a NaN value returns False. Even NaN values are not equal to themselves!
>>> import decimal
>>> a = float("NaN")
>>> b = decimal.Decimal('NaN')
>>> a;b
nan
Decimal('NaN')
>>> a>0
False
>>> a<=0
False
>>> a==b    # Not equal to themselves
False
>>> a!=1    # True because they are not equal to themselves
True
>>> a!=b
True
  • None and NotImplemented are singletons. Comparisons for singletons should always be done with is or is not, and never the equality comparisons.
>>> a = None
>>> a
>>> a is None
True
  • Binary sequences (bytes and bytearray) can be compared within and across their types. They compare lexicographically (character by character) using the numeric values of their elements. That means the first element of each argument are compared. If they equal, then the corresponding second elements are compared.
>>> x = b'abc'
>>> y = b'bcd'
>>> x<y    # a<b is True
True
>>> z = b'ab'
>>> x<z    # a==a, b==b, but c>empty. 
False
>>> a=b'abc'
>>> b=b'b'
>>> a<b
True
  • Strings (str) compare lexicographically (character by character) using the numerical Unicode of the characters. You can find the Unicode of a character using the built-in ord( ) function.
>>> var1 = 'abcd'
>>> var2 = 'bbcd'
>>> ord('a')
97
>>> ord('b')
98
>>> var2>var1
True
>>> var3 = 'bba'
>>> var3>var1
True
>>> var3<var2
True
  • Strings and binary sequences cannot be directly compared.
>>> b'abc' == 'abc'
False
>>> b'abc' <= 'abc'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<=' not supported between instances of 'bytes' and 'str'
>>>
>>> a = b'abc'
>>> b = bytes('abc', 'utf-8')
>>> id(a); id(b)    # Checking the a and b are two different objects
139701914886672
139701919208720
>>> a==b
True
>>> a<=b
True
  • Sequences (instances of list, tuple, or range) can be compared ONLY within each of their own types. But range objects cannot be compared even within their own type. Equality Comparison across them results in inequality and Order Comparison across them raises TypeError.
>>> [1,2,3,4]>[1,2,3]
True
>>> (1,2,3,4)>(1,2,3)
True
>>> range(5)<range(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'range' and 'range'
>>> (1,2,3) == (1,2,3)  # equality comparison within type
True
>>> [1,2,3] == (1,2,3)  # equality comparison across types
False
>>> [1,2,3,4]>[1,2,3]   # Order comparison across types
True
>>> [1,2,3,4]>(1,2,3)   # Order comparison within type
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'list' and 'tuple'

Sequences compare lexicographically using comparison of corresponding elements. Lexical comparison between built-in types works as follows:

  1. For two collections to compare equal (Equality Comparison), they must be of the same type, have the same length, and each pair of the corresponding elements must compare equal.
>>> [1,2,3,4]==[1,2,3,4] # same type, length, each corresponding  pair is equal
True
>>> [1,2,3,4]!=(1,2,3,4) # different types
True
>>> [1,2,3,4]!=[1,2,3]   # different length
True
>>> [1,2,3,4]!=[4,3,2,1] # each corresponding pair is not equal
True
  1. Collections that support Order Comparison are ordered the same as their first unequal elements. For example, [1,2,x,a]<=[1,2,y,b] has the same value as x<=y. A comparison between a and b is completely ignored. If a corresponding element does not exist, then the shorter collection is ordered first. For example, [1,2,3]<[1,2] is true.
>>> [1,2,3,100]<[1,2,4,5]
True
>>> [1,2,3,4] > [1,2,3]
True
>>> [1,2,3,4] < [2]    # The first unequal 
True
  • Dictionaries or Mappings (instances of dict) only supports Equality Comparison. They compare equal if and only if they have equal (key, value) pairs. Order Comparison of them raises TypeError.
>>> {'a':1, 'b':2, 'c':3} == {'a':1.0, 'b':10/5, 'c':2+1}
True
>>> {'a':1, 'b':2, 'c':3} <= {'a':1.0, 'b':10/5, 'c':2+1}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<=' not supported between instances of 'dict' and 'dict'
  • Sets (instances of set and frozenset) can be compared within and across their types. They work the same as sequences. But they define Order Comparison operators in python to mean subset and superset tests.
>>> {1,2}<={1,2}
True
>>> {1,2}<{1,2}
False
>>> {1,2,3}<{1,2}
False
>>> {1,2,3}>{1,2}
True
>>> {1,2,3}!={1,2}
True
>>> [1,2,3]=={1,2,3}
False
  • Equality comparison on floating point numbers may show you unexpected results. Because most of the floating point numbers cannot be represented precisely in the binary number system. That’s why it’s a better idea to use a threshold value when comparing two floating point numbers for equality. For more about this limitation, recall Floating Point Arithmetic: Issues and Limitations from the previous tutorial.
>>> x = 1.1 + 2.2
>>> x
3.3000000000000003
>>> x == 3.3
False
>>> 
>>> # With a threshold or tolerance:
>>> tolerance = 0.00001  # Choice is yours
>>> x = 1.1 + 2.2
>>> abs(x-3.3) < tolerance
True

The built-in abs( ) function returns the absolute value, which is the difference between the actual number and the expected number.


Membership Test Operations: “in”, “not in”

The operators in and not in test for membership, i.e. whether an element is present within an object. x in s returns True if x is a member of s, False otherwise. The operator not in does the opposite.

All built-in sequences, set types, and dictionary support membership test operations.

  • For sequences (list, tuple), set types (set, frozenset), and other container types (such as dict, collections.deque), the in operator tests whether a value exists or not, whereas not in does the opposite.
>>> var1 = [1,2,3,4,5]
>>> 5 in var1
True
>>> 6 not in var1
True
>>> 
>>> popular = {'Python', 'Java', 'C++'}
>>> 'Python' in popular
True
>>> 'Go' not in popular
True
  • For dictionary, in tests whether the dictionary has the given key.
>>> mlwiki = {'name':'MLwiki', 'admin':'Fahim', 'language':'Python'}
>>> 'admin' in mlwiki
True
>>> 'Python' in mlwiki  # Python is not a key
False
>>> 'language' in mlwiki
True
  • For string and byte types, x in s returns True if and only if x is a substring of s. Note that empty strings are always considered to be a substring of any other string. So ” ” in “xyz” will always result in True.
>>> 'w' in 'MLwiki'
True
>>> 'wiki' in 'MLwiki'
True
>>> 'mlwiki' in 'MLwiki'
False
>>> '' in 'MLwiki'
True
>>> ' ' in 'MLwiki'    # ' ' is not empty, it has a whitespace 
False
>>> 'wiki' in b'MLwiki'    # 'wiki' is a string but b'MLwiki' is a byte string.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'str'
>>> b'wiki' in b'MLwiki'
True

Identity Comparisons: “is”, “is not”

The operators is and is not test for an object’s identity. The expression x is y returns True if and only if x and y have the same identity, i.e. they are the same object. Use the id( ) function to check the identity of an object. x is not y returns True if they are different objects.

Be careful when using the identity comparison operators. People tend to make mistakes as they puzzle between is and == operators. is checks whether two objects are actually the same object, where == checks whether the values of two objects are equal. Notice the examples carefully.

>>> num1 = 1001
>>> num2 = 2000-999
>>> id(num1);id(num2)
139877275281936
139877254031280
>>> num1 == num2
True
>>> num1 is num2
False

When practicing this example, try to use a larger number. Because Python caches small numbers (-5 to 256) to increase the performance. Your terminal may cache a larger range of numbers.


Boolean Operators: “or”, “and”, “not”

Boolean operators in Python work almost the same as the binary bitwise operators. Binary bitwise operators work for integers, whereas the Boolean operators work for Boolean values, True and False. Consider 1 as True and 0 as False, then the truth table will be the same. People tend to puzzle between these two types of operators, be careful.

Remember that the following values are interpreted as False. Everything else is True.

  • False
  • None
  • Numeric Zero of all types: 00.00jDecimal(0)Fraction(0, 1)
  • Empty strings and containers: strings, tuples, lists, dictionaries, sets and frozensets

Boolean “or” Operator

The boolean or operator returns True if at least one of the arguments is True. It works from left to right and stops checking the arguments whenever a True value is found. That indicates to the short-circuit evaluation discussed earlier.

>>> True or False
True
>>> True or True
True
>>> False or False or False or True or False
True
>>> 1 or 0   # Non zero value = True
1
>>> 2 or 1   # Both are non-zero, so both are True
2
>>> 3 or 4
3

In practical, you’ll use the Boolean or operator as shown below:

>>> 10>3 or 3>10  # True or False = True
True
>>> 3>10 or 10>3  # False or True = True
True
>>> '' or 'MLwiki' # False or True = True
'MLwiki'
>>> 'ML' or 'Wiki' # True or True = True
'ML'

Boolean “and” Operator

The boolean and operator returns True if all of the arguments are True. It works from left to right and stops checking the arguments whenever a False value is found, i.e. the short-circuit behavior discussed earlier.

>>> True and False
False
>>> True and True
True
>>> True or True or False or True or True
False
>>> 1 and 0    # True and False = False. Hence 0
0
>>> 2 and 1
1
>>> 3 and 4
4
>>> 4 and 3
3

If a False value is present, then False is returned. Otherwise, every True value is checked and the last True value is returned. For example, 2 and 1 returned 1

In practical, you’ll use the Boolean and operator as shown below:

>>> 10>3 and 3>10  # True and False = False
False
>>> 3>10 and 10>3  # False and True = False
False
>>> '' and 'MLwiki' # False and True = False
''
>>> 'ML' and 'Wiki' # True and True = True
'Wiki'

Boolean “not” operator

The boolean not operator changes True to False and vise versa.

>>> not True
False
>>> not False
True
>>> val = True
>>> val is True
True
>>> val is not False
True
>>> not 1
False
>>> not 0
True
>>> not 2
False
>>> not None
True
>>> not 10>3  # Not True
False
>>> not ''    # Not False
True

Note that neither and nor or changes the type and value of its argument to True or False. Rather they return the last evaluated value. That’s why False or 3 or 4 returns 3. On the other hand, True and 3 and 4 returns 4. This characteristic is very useful in Python to set a default value.

As the not operator needs to generate a new value, it always returns a Boolean value regardless of its argument.

Let’s see an example where the Boolean operators can help to get a default value. Notice that for y=0, x/y will raise a ZeroDivisionError and terminate the code execution.

# Bad approach
result = x/y

# Better approach
if y!= 0:
  result = x/y

# Or even better
result = y!=0 and x/y

Another example with the or operator:

>>> Notification = 'Hello!'
>>> message = Notification or 'No Notification'
>>> message
'Hello!'
>>> 
>>> Notification = ''
>>> message = Notification or 'No Notification'
>>> message
'No Notification'

Walrus Operator/ Assignment Expression: “:=”

Walrus Operator, the most controversial Python feature! This feature has been added to Python 3.8 after a whole lot of drama! The majority of the Python core developers were against it, and the drama drove Guido Van Rossum, creator of Python, to step down from his leadership role of Benevolent Dictator for Life (BDFL) after he accepted the walrus operator as part of the PEP 572 proposal.

Although this feature is common in other programming languages, a lot of Python core developers said that it surely reduces the number of lines of code, but it increases the complexity and decreases the readability. Which is against PEP 20, The Zen of Python. Which says:

Simple is better than complex

PEP 20 — The Zen of Python

In my opinion, although this can be very complex depending on how you use it, the walrus operator can be very helpful in certain applications.

So what is this walrus operator or the assignment expression?

The walrus operator does 2 things at once:

  1. Assigns an expression to an identifier (e.g. variable)
  2. Returns the value of the expression

Notice the very basic difference between the assignment statement and the assignment expression:

>>> # Assignment statement
>>> # 1. assign 42 to x
>>> x = 42
>>> x
42
>>> 
>>> # Assignment expression:
>>> # 1. Assigns 42 to x
>>> # 2. returns 42
>>> (x := 42)
42
>>> x
42
>>> 
>>> # Another example
>>> (y := 2**3-4/6)
7.333333333333333
>>> y
7.333333333333333

You must enclose the assignment expression inside parentheses, otherwise it’ll raise an error, SyntaxError: invalid syntax. But if you use the walrus operator inside another expression, such as if statement, while loop, for loop, then you can ignore the parenthesis. Notice the next two examples carefully.

So what are the applications of the walrus operator or the assignment expression?

  • In data science, you need to use regular expressions to extract data matching a certain structure. Here’s how you can do it with and without the assignment expression.
example of walrus operator in data science and regular expression
Assignment Expression
  • While reading a file, the assignment expression might come handy. In the example, the code keeps reading a chunk size data from a file and processing it, until the end of the file is reached.
reading files with walrus operators in python can make you code much cleaner
Assignment Expression

Augmented Assignment Operators in Python

An augmented assignment operator is a combination of the assignment operator (=) and any other operator discussed above that returns a numerical value. This is used to shorten an expression and increase code readability. The concept has been discussed with examples in the previous tutorial, Augmented Assignment Operators in Python. Here, I’ll just list out all the possible augmented assignment operators in Python.

Note that the augmented assignment operators have the least precedence. Check out the proof very carefully.

>>> x = 10
>>> x *= 2+3  # stands for x = x*2+3
>>> x
50
>>> 10*2+3  # Initially x was 10
23
>>> In practical, Python treats augmented assignment like this:
>>> var <operator>= expression  # var = var<operator>(expression)
>>> y = 10
>>> y *= 2+3  # y = y* (2+3)
>>> 10* (2+3)
50

Now check out the table. In each case, consider x=10:

OperatorExampleEquivalentResult
+=x += 3x = x+313
-=x += 3x = x-37
*=x *= 3x = x*330
/=x /= 3x = x/33.33
%=x %= 3x = x%31
//=x //= 3x = x//33
**=x **= 3x = x**31000
&=x &= 3x = x&32
^=x ^= 3x = x^39
|=x |=3x = x|311
<<=x <<= 3x = x<<380
>>=x >>= 3x = x>>31

Last Words

In this tutorial, you learned about every use case of all the operators in Python. Now you not only can use them properly but also aware of the common mistakes people make. For example, the difference between Binary Bitwise Operators (&, ^, |) and Boolean Operators (or, and, not). You also know when to use the is operator over the == operator.

If you didn’t read all the earlier tutorials, here’s a list of recommended ones.

References

Mind Sharing It?
Join Facebook Group

Public Group

A group optimized for learning purposes. Track your progress by joining a unit

Follow on Quora

Public Space

Best place to ask questions! Join the built-in community to get help from others