Python Operators — Complete Reference with Examples

Python BasicsOperatorsFree Lesson

Advertisement

Python Operators — Complete Reference

Operators are special symbols that perform operations on variables and values. Python provides a rich set of operators for different purposes. This guide covers every operator type with practical examples.

Learning Objectives

  • Understand and use all seven categories of Python operators
  • Know the difference between == and is
  • Master short-circuit evaluation with logical operators
  • Use bitwise operators for real-world tasks like permissions and flags
  • Recognize common operator pitfalls and how to avoid them

Arithmetic Operators

Arithmetic operators perform mathematical calculations.

OperatorNameExampleResult
+Addition5 + 38
-Subtraction5 - 32
*Multiplication5 * 315
/Division5 / 31.6667
//Floor Division5 // 31
%Modulo5 % 32
**Power5 ** 3125

Division in Python 3 vs Python 2

In Python 3, / always returns a float:

# Python 3
>>> 10 / 4
2.5

>>> 10 / 2
5.0  # Still a float!

# Python 2 (legacy)
>>> 10 / 4
2  # Integer division (truncated)

Use // when you want integer (floor) division in Python 3:

>>> 10 // 4
2

>>> -10 // 4
-3  # Floors toward negative infinity

Modulo with Negative Numbers

The modulo operator in Python always returns a result with the same sign as the divisor:

>>> 7 % 3
1

>>> -7 % 3
2   # Not -1! Python adjusts to keep result positive

>>> 7 % -3
-2  # Result takes sign of divisor

>>> -7 % -3
-1

This differs from many other languages and can surprise beginners.


Comparison (Relational) Operators

Comparison operators return True or False based on the comparison.

OperatorMeaningExampleResult
==Equal to5 == 5True
!=Not equal to5 != 3True
>Greater than5 > 3True
<Less than5 < 3False
>=Greater or equal5 >= 5True
<=Less or equal5 <= 3False

Chained Comparisons

Python supports chaining multiple comparisons in a single expression:

>>> x = 5
>>> 1 < x < 10
True

>>> 1 < x < 3
False

# Equivalent to:
>>> 1 < x and x < 10
True

# You can chain even more:
>>> 1 < x < 100 > 50
True

This is more readable and often more efficient than using and.

== vs is for None

This is a critical distinction:

>>> x = None
>>> x == None
True

>>> x is None
True

# But be careful:
>>> a = float('nan')
>>> a == a
False  # NaN is never equal to itself

>>> a is a
True   # Identity check still works

Always use is to compare with None, True, or False:

# Correct
if x is None:
    pass

# Incorrect (works but not Pythonic)
if x == None:
    pass

Floating Point Comparison Issues

Floating point arithmetic can produce unexpected results:

>>> 0.1 + 0.2
0.30000000000000004

>>> 0.1 + 0.2 == 0.3
False

Use math.isclose() for float comparisons:

>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True

# With custom tolerance
>>> math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9)
True

Assignment Operators

Assignment operators assign values to variables.

OperatorEquivalentExample
=x = 5x = 5
+=x = x + 5x += 5
-=x = x - 5x -= 5
*=x = x * 5x *= 5
/=x = x / 5x /= 5
//=x = x // 5x //= 5
%=x = x % 5x %= 5
**=x = x ** 5x **= 5

Augmented Assignment with Mutable Types

Be careful with mutable objects:

>>> a = [1, 2, 3]
>>> b = a
>>> a += [4, 5]  # This calls __iadd__ (in-place add)
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3, 4, 5]  # b is affected! Same object

>>> a = [1, 2, 3]
>>> b = a
>>> a = a + [4, 5]  # This creates a NEW list
>>> a
[1, 2, 3, 4, 5]
>>> b
[1, 2, 3]  # b is NOT affected

This happens because += calls __iadd__ which modifies in place for lists, while + creates a new object.


Logical Operators

Logical operators combine conditional statements.

OperatorDescriptionExample
andReturns True if both are TrueTrue and FalseFalse
orReturns True if at least one is TrueTrue or FalseTrue
notReverses the boolean valuenot TrueFalse

Truth Tables

# and truth table
True and True    # True
True and False   # False
False and True   # False
False and False  # False

# or truth table
True or True     # True
True or False    # True
False or True    # True
False or False   # False

# not truth table
not True         # False
not False        # True

Short-Circuit Evaluation

Python evaluates logical operators lazily — it stops as soon as the result is determined:

# 'and' stops at first False
>>> False and print("Never executes")
False

# 'or' stops at first True
>>> True or print("Never executes")
True

Return Values (Not What You Expect)

Logical operators return operands, not necessarily True or False:

>>> 3 and 5
5  # Returns last truthy value

>>> 0 and 5
0  # Returns first falsy value

>>> 3 or 5
3  # Returns first truthy value

>>> 0 or 5
5  # Returns last value if all falsy before

>>> "" or "hello"
'hello'

>>> "hello" or ""
'hello'

The rule:

  • a and b: If a is falsy, return a; otherwise return b
  • a or b: If a is truthy, return a; otherwise return b

Common Patterns

Default values:

>>> name = "" or "Anonymous"
'Anonymous'

>>> name = "Alice" or "Anonymous"
'Alice'

Guard clauses:

# Safe attribute access
>>> users = {"admin": {"role": "super"}}
>>> role = users.get("admin") and users["admin"].get("role")
'super'

>>> role = users.get("missing") and users["missing"].get("role")
None

Conditional assignment:

>>> x = 5
>>> result = x > 10 and "big" or "small"
>>> result
'small'

Bitwise Operators

Bitwise operators work on integers at the binary level.

OperatorNameExampleResult (Binary)
&AND5 & 31 (001)
|OR5 | 37 (111)
^XOR5 ^ 36 (110)
~NOT~5-6
<<Left Shift5 << 220 (10100)
>>Right Shift5 >> 21 (1)

Truth Tables

# AND (&): Both bits must be 1
>>> 0b1010 & 0b1100  # 10 & 12
0b1000  # 8

# OR (|): At least one bit must be 1
>>> 0b1010 | 0b1100  # 10 | 12
0b1110  # 14

# XOR (^): Bits must be different
>>> 0b1010 ^ 0b1100  # 10 ^ 12
0b0110  # 6

# NOT (~): Flips all bits
>>> ~5
-6  # Equivalent to -(n+1)

# Left Shift: Multiply by 2^n
>>> 5 << 2  # 5 * 2^2
20

# Right Shift: Integer divide by 2^n
>>> 20 >> 2  # 20 // 2^2
5

Real-World Uses: Flags and Permissions

Bitwise operators are commonly used for feature flags and permissions:

# Define permission flags
READ    = 0b001  # 1
WRITE   = 0b010  # 2
EXECUTE = 0b100  # 4

# Combine permissions
user_permissions = READ | WRITE  # 0b011 = 3

# Check permissions
has_read = bool(user_permissions & READ)     # True
has_execute = bool(user_permissions & EXECUTE) # False

# Add permission
user_permissions |= EXECUTE  # 0b111 = 7

# Remove permission
user_permissions &= ~WRITE  # 0b101 = 5

# Toggle permission
user_permissions ^= READ  # 0b100 = 4

# Check if multiple permissions set
needs = READ | WRITE
has_all = (user_permissions & needs) == needs  # False

Membership Operators

Membership operators test if a value is found in a sequence.

OperatorDescriptionExample
inReturns True if value is in sequence3 in [1, 2, 3]True
not inReturns True if value is not in sequence3 not in [1, 2, 3]False

With Different Types

# Lists
>>> 3 in [1, 2, 3, 4, 5]
True

>>> "x" in ["a", "b", "c"]
False

# Strings (substring check)
>>> "py" in "python"
True

>>> "Python" in "python"
False  # Case-sensitive!

# Tuples
>>> 10 in (10, 20, 30)
True

# Dictionaries (checks keys, not values!)
>>> "name" in {"name": "Alice", "age": 30}
True

>>> "Alice" in {"name": "Alice", "age": 30}
False  # Check values with .values()

# Sets (most efficient membership testing)
>>> 3 in {1, 2, 3, 4, 5}
True

# Range
>>> 5 in range(10)
True

>>> 10 in range(10)
False  # range(10) is 0-9

__contains__ Protocol

When you use in, Python calls the __contains__ method:

class Fibonacci:
    def __init__(self, limit):
        self.limit = limit
        self.fibs = [0, 1]
        while self.fibs[-1] < limit:
            self.fibs.append(self.fibs[-1] + self.fibs[-2])

    def __contains__(self, item):
        return item in self.fibs

>>> fib = Fibonacci(100)
>>> 21 in fib
True
>>> 22 in fib
False

Identity Operators

Identity operators check if two variables point to the same object in memory.

OperatorDescriptionExample
isTrue if both reference same objecta is b
is notTrue if they reference different objectsa is not b

Integer CPython Caching

CPython caches integers from -5 to 256 for performance:

>>> a = 256
>>> b = 256
>>> a is b
True  # Same cached object

>>> a = 257
>>> b = 257
>>> a is b
False  # Different objects (usually)

# This behavior is implementation-specific and shouldn't be relied upon

String Interning

Python interns (reuses) strings that look like identifiers:

>>> a = "hello"
>>> b = "hello"
>>> a is b
True  # Interned

>>> a = "hello world"
>>> b = "hello world"
>>> a is b
True  # Also interned (contains only identifier chars)

>>> a = "hello!"
>>> b = "hello!"
>>> a is b
False  # Contains non-identifier char, not interned

When to Use is vs ==

Use is for:

  • Checking None: if x is None:
  • Checking True/False: if flag is True:
  • Checking sentinels: if result is MISSING:

Use == for:

  • Everything else (value comparison)
# Correct
if x is None:
    pass

if result is not True:
    pass

# Incorrect (may fail with custom __eq__)
if x == None:  # Works but not Pythonic
    pass

Operator Precedence

From highest to lowest:

PrecedenceOperatorsDescription
1()Parentheses (grouping)
2**Exponentiation
3~, +x, -xBitwise NOT, unary plus/minus
4*, /, //, %Multiplication, division, floor div, modulo
5+, -Addition, subtraction
6<<, >>Bitwise shifts
7&Bitwise AND
8^Bitwise XOR
9|Bitwise OR
10==, !=, >, <, >=, <=, is, is not, in, not inComparisons
11notLogical NOT
12andLogical AND
13orLogical OR

Parentheses for Clarity

Always use parentheses when precedence is unclear:

# Avoid this
>>> 2 + 3 * 4
14

# Prefer this
>>> 2 + (3 * 4)
14

# Essential with mixed operators
>>> (x > 5) and (y < 10)

# Without parentheses - harder to read
>>> x > 5 and y < 10

Special Operator Behaviors

String Repetition with *

The * operator repeats strings:

>>> "ha" * 3
'hahaha'

>>> "-" * 20
'--------------------'

>>> 3 * "py"
'pypypy'

List Repetition with *

Lists can also be repeated:

>>> [0] * 5
[0, 0, 0, 0, 0]

>>> [1, 2] * 3
[1, 2, 1, 2, 1, 2]

# Be careful with nested lists!
>>> a = [[0]] * 3
>>> a
[[0], [0], [0]]

>>> a[0].append(1)
>>> a
[[0, 1], [0, 1], [0, 1]]  # All sublists are the same object!

# Correct way
>>> b = [[0] for _ in range(3)]
>>> b[0].append(1)
>>> b
[[0, 1], [0], [0]]  # Independent sublists

Operator Overloading Preview

Python allows custom classes to define operator behavior:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

>>> v1 = Vector(1, 2)
>>> v2 = Vector(3, 4)
>>> v1 + v2
Vector(4, 6)
>>> v1 * 3
Vector(3, 6)

Common Mistakes

Mistake 1: Using = Instead of ==

x = 5
# Wrong: assignment in condition
if x = 5:  # SyntaxError
    print("yes")

# Correct
if x == 5:
    print("yes")

Mistake 2: Chained Comparison with and

# Wrong (looks right but behaves differently)
>>> x = 5
>>> 1 < x and x < 10
True

# This looks similar but isn't:
>>> 1 < x < 10  # Actually equivalent to above (good)
True

# The gotcha: logical operators return operands
>>> 1 and 2 and 3
3

>>> 0 and 2 and 3
0

Mistake 3: Mutable Default with *

# Wrong: shared mutable default
>>> def append_to(item, lst=[]):
...     lst.append(item)
...     return lst

>>> append_to(1)
[1]
>>> append_to(2)
[1, 2]  # Not [2]! List persists between calls

# Correct
>>> def append_to(item, lst=None):
...     if lst is None:
...         lst = []
...     lst.append(item)
...     return lst

Mistake 4: Float Comparison with ==

# Wrong
>>> 0.1 + 0.2 == 0.3
False

# Correct
>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True

Mistake 5: Confusing in with Dictionaries

>>> d = {"name": "Alice", "age": 30}

# Wrong: checking values instead of keys
>>> "Alice" in d
False

# Correct: 'in' checks keys
>>> "name" in d
True

# To check values
>>> "Alice" in d.values()
True

Practice Exercises

Exercise 1: Temperature Converter

Write a function that converts Celsius to Fahrenheit and determines if the water is boiling (>= 100°C / 212°F).

def check_boiling(celsius):
    fahrenheit = celsius * 9/5 + 32
    is_boiling = celsius >= 100
    return fahrenheit, is_boiling

# Test
temp_f, boiling = check_boiling(100)
print(f"{temp_f}°F, Boiling: {boiling}")
# Output: 212.0°F, Boiling: True

temp_f, boiling = check_boiling(25)
print(f"{temp_f}°F, Boiling: {boiling}")
# Output: 77.0°F, Boiling: False

Exercise 2: Permission Checker

Create a function that checks what operations a user can perform based on permission flags.

READ = 1
WRITE = 2
EXECUTE = 4

def check_permissions(user_flags):
    can_read = bool(user_flags & READ)
    can_write = bool(user_flags & WRITE)
    can_execute = bool(user_flags & EXECUTE)

    permissions = []
    if can_read:
        permissions.append("read")
    if can_write:
        permissions.append("write")
    if can_execute:
        permissions.append("execute")

    return permissions

# Test
print(check_permissions(READ | WRITE))           # ['read', 'write']
print(check_permissions(READ | EXECUTE))          # ['read', 'execute']
print(check_permissions(READ | WRITE | EXECUTE))  # ['read', 'write', 'execute']
print(check_permissions(0))                        # []

Exercise 3: Data Validator

Write a validator that checks if data meets multiple conditions using logical operators.

def validate_user(data):
    has_name = bool(data.get("name"))
    has_email = "@" in data.get("email", "")
    age = data.get("age", 0)
    valid_age = 18 <= age <= 120

    is_valid = has_name and has_email and valid_age
    errors = []

    if not has_name:
        errors.append("Name required")
    if not has_email:
        errors.append("Valid email required")
    if not valid_age:
        errors.append("Age must be 18-120")

    return is_valid, errors

# Test
valid, errors = validate_user({
    "name": "Alice",
    "email": "alice@example.com",
    "age": 25
})
print(f"Valid: {valid}, Errors: {errors}")
# Output: Valid: True, Errors: []

valid, errors = validate_user({
    "name": "",
    "email": "invalid",
    "age": 15
})
print(f"Valid: {valid}, Errors: {errors}")
# Output: Valid: False, Errors: ['Name required', 'Valid email required', 'Age must be 18-120']

Key Takeaways

  1. Division: / always returns a float in Python 3; use // for floor division
  2. Modulo with negatives: Returns result with the same sign as the divisor
  3. Chained comparisons: 1 < x < 10 is cleaner than 1 < x and x < 10
  4. == vs is: Use is for None/True/False checks; == for value comparison
  5. Logical operators return operands: 0 or "hello" returns "hello", not True
  6. Short-circuit evaluation: and stops at first falsy; or stops at first truthy
  7. Membership testing: in on dictionaries checks keys, not values
  8. Integer caching: is may work for small integers but shouldn't be relied upon
  9. Bitwise operators: Essential for flags, permissions, and low-level operations
  10. Use parentheses: When operator precedence is unclear, always use parentheses for clarity

Next: Python Strings — Learn about string manipulation, formatting, and methods.

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement