Python Operators

Master all Python operators: arithmetic, comparison, logical, bitwise, identity, membership, and the walrus operator :=.

Beginner 10 min read 10 examples

Arithmetic Operators

Python supports all standard arithmetic operations plus floor division, exponentiation, and modulo.

Python
a, b = 17, 5

print(a + b)    # 22  - addition
print(a - b)    # 12  - subtraction
print(a * b)    # 85  - multiplication
print(a / b)    # 3.4 - true division (always float)
print(a // b)   # 3   - floor division (rounds toward -inf)
print(a % b)    # 2   - modulo (remainder)
print(a ** b)   # 1419857 - exponentiation (a to the power b)
print(-a)       # -17 - unary negation

# True division vs floor division
print(7 / 2)    # 3.5
print(7 // 2)   # 3
print(-7 // 2)  # -4  (floor toward negative infinity, not -3)

# Modulo with negative numbers
print(17 % 5)   # 2   (17 = 3*5 + 2)
print(-17 % 5)  # 3   (result has same sign as divisor in Python)

# Exponentiation
print(2 ** 10)  # 1024
print(9 ** 0.5) # 3.0  (square root)
print(2 ** -1)  # 0.5  (negative exponent)

# Integer arithmetic preserves type
print(type(10 // 3))    # 
print(type(10.0 // 3))  # 
print(type(10 / 3))     #   (always float)
OperatorNameExampleResult
+Addition7 + 310
-Subtraction7 - 34
*Multiplication7 * 321
/True division7 / 23.5
//Floor division7 // 23
%Modulo7 % 31
**Exponentiation2 ** 8256

Comparison Operators

Comparison operators return True or False. Python supports chained comparisons, a feature not available in most languages.

Python
x, y = 10, 20

print(x == y)   # False - equal to
print(x != y)   # True  - not equal to
print(x < y)    # True  - less than
print(x > y)    # False - greater than
print(x <= y)   # True  - less than or equal to
print(x >= y)   # False - greater than or equal to

# Chained comparisons - a unique Python feature
age = 25
print(18 <= age < 65)   # True  - legal working age
print(0 < x < y < 100)  # True  - all three conditions

# Equivalent without chaining (more verbose)
print(18 <= age and age < 65)   # True

# String comparison (lexicographic / Unicode order)
print("apple" < "banana")   # True  - 'a' < 'b'
print("abc" == "abc")       # True
print("Z" < "a")            # True  - uppercase letters come before lowercase in Unicode

# Comparing different types raises TypeError in Python 3
# print(5 < "5")  # TypeError: '<' not supported between 'int' and 'str'

# List comparison (element by element)
print([1, 2, 3] == [1, 2, 3])  # True
print([1, 2, 4] > [1, 2, 3])   # True  - 4 > 3 at index 2

Logical Operators

Python uses words and, or, not instead of &&, ||, !. These operators use short-circuit evaluation and return an operand, not necessarily a boolean.

Python
# Basic boolean logic
print(True and True)    # True
print(True and False)   # False
print(False or True)    # True
print(False or False)   # False
print(not True)         # False
print(not False)        # True

# Short-circuit evaluation
# 'and' returns first falsy value, or the last value
print(0 and "hello")    # 0       (0 is falsy, stop here)
print(5 and "hello")    # hello   (5 is truthy, evaluate right side)
print(5 and 10)         # 10      (both truthy, return last)

# 'or' returns first truthy value, or the last value
print(0 or "hello")     # hello   (0 is falsy, try right side)
print(5 or "hello")     # 5       (5 is truthy, stop here)
print(0 or False)       # False   (both falsy, return last)

# Practical uses
name = ""
display = name or "Anonymous"   # "Anonymous" - default value pattern
print(display)

user = {"admin": True}
is_admin = user.get("admin") and user["admin"]   # safe access pattern

# not always returns True or False
print(not 0)        # True
print(not "hello")  # False
print(not [])       # True  - empty list is falsy
print(not [1, 2])   # False - non-empty list is truthy

# Combining with comparisons
x = 15
print(x > 10 and x < 20)   # True  - x is between 10 and 20
print(x < 5 or x > 10)     # True  - x is outside 5-10 range

Assignment Operators

In addition to plain =, Python has augmented assignment operators that combine an operation with assignment.

Python
x = 10

x += 3   # x = x + 3  -> 13
x -= 2   # x = x - 2  -> 11
x *= 4   # x = x * 4  -> 44
x /= 2   # x = x / 2  -> 22.0  (always float)
x //= 3  # x = x // 3 -> 7.0
x %= 3   # x = x % 3  -> 1.0
x **= 4  # x = x ** 4 -> 1.0

# Augmented assignment on strings
greeting = "Hello"
greeting += ", World"
print(greeting)     # Hello, World

# Augmented assignment on lists
items = [1, 2, 3]
items += [4, 5]     # extends in place (like extend())
print(items)        # [1, 2, 3, 4, 5]

items *= 2          # repeats the list
print(items)        # [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

# Logical assignment operators (Python 3.8+)
# ||=, &&=, ??= equivalents
config = {}
config["retries"] = config.get("retries") or 3   # old way

# Walrus-style initialization (3.8+)
config.setdefault("timeout", 30)    # sets only if key is missing

# Python does NOT have ++ or -- operators
# Use x += 1 and x -= 1 instead
count = 0
count += 1   # correct
# count++    # SyntaxError
OperatorEquivalentExample
+=x = x + nx += 5
-=x = x - nx -= 5
*=x = x * nx *= 5
/=x = x / nx /= 5
//=x = x // nx //= 5
%=x = x % nx %= 5
**=x = x ** nx **= 2

Bitwise Operators

Bitwise operators work on the binary representation of integers. They are used in low-level programming, flags, and performance-critical code.

Python
# a = 0b1010 = 10
# b = 0b1100 = 12
a = 0b1010   # 10
b = 0b1100   # 12

print(a & b)    # 0b1000 = 8  - AND: bits set in both
print(a | b)    # 0b1110 = 14 - OR:  bits set in either
print(a ^ b)    # 0b0110 = 6  - XOR: bits set in one but not both
print(~a)       # -11         - NOT: flip all bits (-(a+1))

# Bit shifts
print(a << 2)   # 40  - left shift  by 2 (multiply by 4)
print(a >> 1)   # 5   - right shift by 1 (divide by 2)

# Practical: check if a number is odd
def is_odd(n):
    return bool(n & 1)   # last bit is 1 if odd

print(is_odd(7))   # True
print(is_odd(8))   # False

# Practical: flag system (permissions)
READ    = 0b001  # 1
WRITE   = 0b010  # 2
EXECUTE = 0b100  # 4

user_perms = READ | WRITE       # 3 (has read and write)
print(bool(user_perms & READ))     # True  - can read
print(bool(user_perms & EXECUTE))  # False - cannot execute

# Add a permission
user_perms |= EXECUTE           # set execute bit
print(bool(user_perms & EXECUTE))  # True

# Remove a permission
user_perms &= ~WRITE            # clear write bit
print(bool(user_perms & WRITE))    # False

# Display binary representation
print(bin(42))      # 0b101010
print(format(42, 'b'))   # 101010
print(f"{42:08b}")  # 00101010  (8-bit padded)

Identity and Membership Operators

Python
# --- Identity operators: is, is not ---
# Tests whether two names refer to the SAME object in memory

a = [1, 2, 3]
b = [1, 2, 3]   # same content, different object
c = a            # same object

print(a == b)    # True  - same values
print(a is b)    # False - different objects
print(a is c)    # True  - same object (c points to a)

# The only recommended use of 'is': checking for None
x = None
print(x is None)      # True  - correct way
print(x is not None)  # False

# Small integer caching (CPython implementation detail)
# Integers from -5 to 256 are cached - don't rely on this
p = 256
q = 256
print(p is q)   # True  (cached in CPython)
r = 257
s = 257
print(r is s)   # False (may vary - not cached)

# --- Membership operators: in, not in ---
# Tests whether a value is in a sequence or collection

fruits = ["apple", "banana", "cherry"]
print("banana" in fruits)       # True
print("grape" not in fruits)    # True

# Works on strings (substring check)
message = "Hello, World!"
print("World" in message)       # True
print("world" in message)       # False - case sensitive

# Works on dicts (checks keys by default)
person = {"name": "Alice", "age": 30}
print("name" in person)         # True
print("Alice" in person)        # False - checks keys, not values
print("Alice" in person.values())   # True

# Works on sets (O(1) lookup - faster than lists)
allowed_roles = {"admin", "editor", "viewer"}
print("admin" in allowed_roles)    # True
print("hacker" in allowed_roles)   # False
Use == for value comparisons, is for None

Never use is to compare values like strings or numbers - it checks object identity, not equality. "hello" is "hello" may be True in a REPL due to string interning, but this is an implementation detail you cannot rely on. The rule: use is only for None, True, and False. Use == for everything else.

Walrus Operator :=

The walrus operator := (assignment expression, added in Python 3.8) assigns a value to a variable and returns that value in a single expression. It is named after a walrus because := resembles a walrus face.

Python
# --- while loop: read until empty ---
# Without walrus - must duplicate the read call
data = input("Enter text (blank to stop): ")
while data:
    print(f"You entered: {data}")
    data = input("Enter text (blank to stop): ")

# With walrus - cleaner, no duplication
while data := input("Enter text (blank to stop): "):
    print(f"You entered: {data}")

# --- File reading in chunks ---
import io

# Without walrus
f = io.BytesIO(b"hello world this is test data")
chunk = f.read(8)
while chunk:
    print(chunk)
    chunk = f.read(8)

# With walrus
f = io.BytesIO(b"hello world this is test data")
while chunk := f.read(8):
    print(chunk)

# --- Conditional assignment ---
import re

text = "Order #12345 placed"

# Without walrus
match = re.search(r"#(\d+)", text)
if match:
    order_id = match.group(1)
    print(f"Order ID: {order_id}")

# With walrus - assign and test in one line
if match := re.search(r"#(\d+)", text):
    print(f"Order ID: {match.group(1)}")   # match is available here

# --- List comprehension with expensive computation ---
def expensive(x):
    return x * x   # simulating an expensive operation

# Without walrus - compute twice
results = [y for x in range(10) if x * x > 20 for y in [x * x]]

# With walrus - compute once
results = [y for x in range(10) if (y := expensive(x)) > 20]
print(results)   # [25, 36, 49, 64, 81]
Use walrus sparingly for readability

The walrus operator is powerful but can reduce readability if overused. It shines in while loops that read data and in if statements where you want to both match and capture. Avoid it in simple assignments or when a regular assignment is clearer. PEP 572 recommends: if in doubt, use a regular assignment statement instead.

Operator Precedence

Python evaluates operators in a specific order. Higher precedence operators are evaluated first. When in doubt, use parentheses to make intent explicit.

PrecedenceOperator(s)Description
1 (highest)()Parentheses
2**Exponentiation (right-to-left)
3+x -x ~xUnary plus, minus, bitwise NOT
4* / // %Multiplication, division, floor div, modulo
5+ -Addition, subtraction
6<< >>Bit shifts
7&Bitwise AND
8^Bitwise XOR
9|Bitwise OR
10== != < > <= >= is inComparisons, identity, membership
11notLogical NOT
12andLogical AND
13 (lowest)orLogical OR
Python
# Precedence examples
print(2 + 3 * 4)        # 14  (not 20) - * before +
print((2 + 3) * 4)      # 20  - parentheses first
print(2 ** 3 ** 2)      # 512 (not 64) - ** is right-to-left: 2**(3**2) = 2**9
print((2 ** 3) ** 2)    # 64  - explicit left-to-right

print(not 0 == 0)       # True - (not 0) == 0 -> True == 0 -> hmm...
# Actually: not (0 == 0) -> not True -> False  (== has higher precedence than not)
print(not (0 == 0))     # False

# This is tricky - always use parentheses with not
x = 5
print(not x > 3)        # False - parsed as not (x > 3) - not (True) = False

# Logical short-circuit order matters
def side_effect():
    print("called!")
    return True

print(False and side_effect())  # False - side_effect never called
print(True  or  side_effect())  # True  - side_effect never called

Frequently Asked Questions

/ always performs true (float) division: 7 / 2 gives 3.5. // performs floor division - it divides and rounds down to the nearest integer: 7 // 2 gives 3. Floor division works on floats too: 7.5 // 2 gives 3.0. Note that floor division rounds toward negative infinity, not toward zero: -7 // 2 gives -4, not -3.

The walrus operator := (assignment expression, added in Python 3.8) assigns a value to a variable and returns that value in the same expression. It is useful in while loops and comprehensions where you want to assign and test in one step. For example: while chunk := file.read(8192): reads a chunk and continues the loop as long as the chunk is non-empty. Without walrus, you would need to read before the loop and again at the end of the loop body.

== checks value equality - whether two objects have the same value. is checks identity - whether two names point to the exact same object in memory. For example, [1, 2] == [1, 2] is True (same values), but [1, 2] is [1, 2] is False (different objects). Always use == for value comparisons. Use is only to check against None (if x is None:), True, or False.

Python's and and or return one of their operands, not necessarily True/False. x or y returns x if x is truthy, otherwise returns y. x and y returns x if x is falsy, otherwise returns y. This enables idioms like name = user_input or "default". not always returns a boolean.