Python Operators — Arithmetic, Comparison, Logical, and Bitwise Guide
Advertisement
Introduction
Why This Matters
Operators are the fundamental building blocks of expressions in Python. Every calculation, comparison, and logical decision in your code relies on operators. While basic arithmetic is obvious, Python has a rich set of operators — bitwise, identity, membership, and the walrus operator — that are powerful but often misunderstood.
Understanding operator precedence prevents subtle bugs where expressions evaluate in an unexpected order. Knowing the difference between == and is, or between and and &, is essential for writing correct Python. These distinctions are also common interview topics because they reveal depth of language knowledge.
Arithmetic Operators
a, b = 10, 3
print(a + b) # 13 — addition
print(a - b) # 7 — subtraction
print(a * b) # 30 — multiplication
print(a / b) # 3.3333... — true division (always returns float)
print(a // b) # 3 — floor division (integer result)
print(a % b) # 1 — modulo (remainder)
print(a ** b) # 1000 — exponentiation
# Useful patterns
print(17 % 12) # 5 — clock arithmetic
print(-7 % 3) # 2 — Python modulo is always non-negative for positive divisor
print(2 ** 10) # 1024
print(100 ** 0.5) # 10.0 — square root via exponentiationComparison Operators
x, y = 5, 10
print(x == y) # False — equal
print(x != y) # True — not equal
print(x < y) # True — less than
print(x > y) # False — greater than
print(x <= y) # True — less than or equal
print(x >= y) # False — greater than or equal
# Chained comparisons (Pythonic)
age = 25
print(18 <= age <= 65) # True — between 18 and 65
print(1 < 2 < 3 < 4) # True — all TrueLogical Operators
# and, or, not
print(True and False) # False
print(True or False) # True
print(not True) # False
# Short-circuit evaluation
def risky():
raise ValueError("Should not be called")
print(False and risky()) # False — risky() never called
print(True or risky()) # True — risky() never called
# Practical use
user = None
name = user and user["name"] # safely avoid AttributeError
value = user or "default" # fallback valueAssignment Operators
x = 10
x += 5 # x = x + 5 → 15
x -= 3 # x = x - 3 → 12
x *= 2 # x = x * 2 → 24
x //= 5 # x = x // 5 → 4
x **= 3 # x = x ** 3 → 64
x %= 10 # x = x % 10 → 4Identity Operators: is and is not
is checks whether two variables point to the same object, not equal values.
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True — same values
print(a is b) # False — different objects in memory
print(a is c) # True — same object
# None comparison — always use 'is'
result = None
if result is None: # correct
pass
if result == None: # works but not idiomatic
pass
# CPython interns small integers and short strings
x = 256
y = 256
print(x is y) # True — CPython caches -5 to 256
x = 257
y = 257
print(x is y) # False — not cached (implementation detail)Membership Operators: in and not in
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # True
print("mango" not in fruits) # True
# String membership
print("py" in "python") # True
print("xyz" not in "hello") # True
# Dict membership (checks keys)
config = {"host": "localhost", "port": 5432}
print("host" in config) # True
print("password" in config) # False
# Set membership — O(1) lookup
tags = {"python", "web", "api"}
print("python" in tags) # True — fastest membership testBitwise Operators
a = 0b1100 # 12
b = 0b1010 # 10
print(bin(a & b)) # 0b1000 (8) — AND
print(bin(a | b)) # 0b1110 (14) — OR
print(bin(a ^ b)) # 0b0110 (6) — XOR
print(bin(~a)) # -0b1101 — NOT (bitwise complement)
print(bin(a << 1)) # 0b11000 (24) — left shift (multiply by 2)
print(bin(a >> 1)) # 0b110 (6) — right shift (divide by 2)
# Practical: check if number is even
def is_even(n: int) -> bool:
return (n & 1) == 0
# Practical: swap without temp variable
x, y = 5, 10
x, y = x ^ y, x ^ y ^ (x ^ y) # works but use tuple swap instead
x, y = y, x # simpler and more PythonicWalrus Operator := (Python 3.8+)
The walrus operator assigns a value in an expression.
# Without walrus
data = get_data()
if data:
process(data)
# With walrus (assign and check in one)
if data := get_data():
process(data)
# In while loops
import re
text = "Hello 42 World 17"
pos = 0
while match := re.search(r"\d+", text[pos:]):
print(match.group())
pos += match.end()
# In comprehensions
values = [1, 2, 3, 4, 5, 6]
# Find and use transformed values
results = [y for x in values if (y := x ** 2) > 10]
# [16, 25, 36]Operator Precedence (High to Low)
| Operators | Description |
|---|---|
** | Exponentiation |
+x, -x, ~x | Unary |
*, /, //, % | Multiplication, division |
+, - | Addition, subtraction |
<<, >> | Bitwise shift |
& | Bitwise AND |
^ | Bitwise XOR |
| | Bitwise OR |
==, !=, <, >, <=, >=, is, in | Comparisons |
not | Logical NOT |
and | Logical AND |
or | Logical OR |
:= | Walrus |
Common Mistakes
- Using
==to compare toNoneinstead ofis - Confusing
and/or(logical) with&/|(bitwise) — different behavior - Expecting
/to return an integer — use//for floor division - Misunderstanding modulo with negative numbers
- Forgetting that
not inis two words, not!in
Best Practices
- Use
isandis notforNone,True, andFalsecomparisons - Use parentheses to make complex expressions explicit rather than relying on precedence
- Prefer
//overint(a / b)for integer division - Use the walrus operator to simplify repetitive assignment patterns
- Use
inwith sets for O(1) membership checks instead of lists
Key Takeaways
- Python's
/always returns a float;//returns the floor integer result iscompares object identity;==compares values — useisforNone/True/Falseand/orare logical operators with short-circuit evaluation;&/|are bitwiseinandnot intest membership in sequences, sets, and dict keys- The walrus operator
:=assigns and returns a value in a single expression (Python 3.8+) - Chained comparisons like
1 < x < 10work naturally in Python - When in doubt about precedence, use parentheses to be explicit
Advertisement