Skip to main content
Python beginner Lesson 8 of 28

Python Operators

Learn Python's arithmetic, comparison, logical, bitwise, and walrus operators with practical examples.

Arithmetic Operators

Arithmetic operators perform the numeric computations you’d expect, with a few Python-specific behaviors worth knowing: / always returns a float, ** is right-associative, and % follows the sign of the divisor (not the dividend) for negative numbers.

a, b = 10, 3

a + b    # 13       — addition
a - b    # 7        — subtraction
a * b    # 30       — multiplication
a / b    # 3.3333…  — true division: always returns a float
a // b   # 3        — floor division: rounds toward negative infinity
a % b    # 1        — modulo: remainder after floor division
a ** b   # 1000     — exponentiation

# Augmented assignment operators — modify in place
x = 5
x += 3   # x = 8
x *= 2   # x = 16
x //= 3  # x = 5
x **= 2  # x = 25

Operator Precedence (High to Low)

Operator precedence determines how expressions are parsed when no parentheses are used. In practice, use parentheses to make your intent explicit — relying on memorized precedence rules makes code harder to read and review.

**            exponentiation (right-associative)
+x, -x, ~x   unary operators
*, /, //, %   multiplication, division
+, -          addition, subtraction
<<, >>        bitwise shift
&             bitwise AND
^             bitwise XOR
|             bitwise OR
==, !=, <, >, <=, >=, is, is not, in, not in
not           logical NOT
and           logical AND
or            logical OR
:=            walrus

Comparison Operators

Comparison operators return a boolean and are the backbone of every conditional statement. Python supports chained comparisons — a feature that reads naturally and avoids repeating the variable name.

5 == 5     # True
5 != 4     # True
5 > 3      # True
5 < 3      # False
5 >= 5     # True
5 <= 4     # False

# Chained comparisons — very Pythonic, equivalent to using 'and'
x = 7
1 < x < 10    # True  — same as (1 < x) and (x < 10)
0 <= x <= 5   # False

# Equivalent long form:
1 < x and x < 10

Identity vs Equality

== checks whether two objects have equal values. is checks whether they are the exact same object in memory. The distinction matters most with mutable objects and None.

a = [1, 2, 3]
b = [1, 2, 3]
c = a

a == b    # True  — same values
a is b    # False — different list objects, even though values match
a is c    # True  — c is another name for the same object as a

# Correct None check — always use 'is' because None is a singleton
value = None
value is None      # True  (correct — checks identity)
value == None      # True  (works, but misleading — use 'is')

Logical Operators

Logical operators combine boolean expressions. They return one of their operands — not necessarily True or False — which enables a useful set of idioms for default values.

True and False    # False
True or False     # True
not True          # False

Short-Circuit Evaluation

Python evaluates and/or lazily, stopping as soon as the result is determined. This means the right-hand side of an and is never evaluated if the left is falsy, and the right-hand side of an or is never evaluated if the left is truthy. This has real performance and safety implications.

# 'and' stops at the first falsy value — expensive_function() never runs
False and expensive_function()

# 'or' stops at the first truthy value — expensive_function() never runs
True or expensive_function()

# Practical use: provide default values without if/else
name = user_input or "Anonymous"          # use "Anonymous" if user_input is empty
config = provided_config or load_default()  # only call load_default() if needed

Truthiness in Conditions

Python evaluates any object as truthy or falsy in a boolean context, not just explicit True/False. Writing if items: instead of if len(items) > 0: is idiomatic Python and slightly faster.

items = []
if not items:
    print("Empty list")  # idiomatic — leverages truthiness

user = None
if user is None:         # use 'is' for None, not truthiness
    print("Not logged in")

# or-assignment: assign a default if the left side is falsy
settings = user_settings or {}

Membership Operators

Membership operators test whether a value exists inside a collection. They work across all sequence and collection types — but the underlying time complexity differs significantly by type.

"a" in "alphabet"        # True   — substring check
"z" in "alphabet"        # False
"z" not in "alphabet"    # True

3 in [1, 2, 3, 4]       # True   — list scan: O(n)
5 not in {1, 2, 3}      # True   — set lookup: O(1)

# Dict membership checks keys, not values
"name" in {"name": "Alice", "age": 30}   # True  — "name" is a key
"Alice" in {"name": "Alice"}             # False — "Alice" is a value, not a key

in on a set or dict is O(1) because they’re backed by hash tables. On a list, it’s O(n) because Python scans every element. When you’re doing many membership checks, convert to a set first.

Bitwise Operators

Bitwise operators work directly on the binary representation of integers. They’re essential for low-level programming tasks: permission flags, network masks, hardware register manipulation, and compact storage of boolean fields.

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

a & b    # 0b1000 = 8   — AND: bits set in both a and b
a | b    # 0b1110 = 14  — OR: bits set in either a or b
a ^ b    # 0b0110 = 6   — XOR: bits set in one but not both
~a       # -11           — NOT: inverts all bits (two's complement)
a << 1   # 20            — left shift: equivalent to multiplying by 2
a >> 1   # 5             — right shift: equivalent to integer division by 2

Practical Bitwise Use: Permission Flags

Using a single integer as a compact set of boolean flags is a pattern you’ll see in OS APIs, file systems, and network protocols. Each bit represents one permission, and you can combine or test permissions with a single operation.

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

# Grant read and write by OR-ing the flags together
permissions = READ | WRITE   # 0b011 = 3

# Test a permission with AND — non-zero means the bit is set
has_read    = bool(permissions & READ)      # True
has_execute = bool(permissions & EXECUTE)   # False

# Revoke write by AND-ing with the bitwise NOT of WRITE
permissions &= ~WRITE   # 0b001 = 1 — write bit cleared

The Walrus Operator (:=)

Introduced in Python 3.8, := assigns a value to a variable and returns that value in the same expression. It solves a specific problem: when you need to compute a value, check it, and then use it — without computing it twice or writing extra setup code.

In a while Loop

# Without walrus — reads chunk, then checks chunk separately
while True:
    chunk = file.read(1024)
    if not chunk:
        break
    process(chunk)

# With walrus — read and check in the same expression
while chunk := file.read(1024):
    process(chunk)

In Comprehensions

import re

data = ["user@example.com", "invalid", "admin@company.org", "bad"]

# Without walrus — the regex runs twice for each match: once to filter, once to use
valid = [m.group() for s in data if re.match(r"\w+@\w+\.\w+", s)
         for m in [re.match(r"\w+@\w+\.\w+", s)]]

# With walrus — compute once, use in both the condition and the value
valid = [m.group() for s in data if (m := re.match(r"\w+@\w+\.\w+", s))]
# ["user@example.com", "admin@company.org"]

In if Statements

import json

raw = '{"name": "Alice", "age": 30}'

# Parse and use the result without a separate assignment line
if data := json.loads(raw):
    print(f"Loaded: {data['name']}")

Ternary (Conditional) Expression

Python’s inline conditional expression provides a compact way to express simple if/else logic in a single line. It reads like natural English: “value if condition else other-value.”

x = 10
label = "even" if x % 2 == 0 else "odd"   # "even"

# Nested ternary — use sparingly, it hurts readability quickly
grade = "A" if score >= 90 else "B" if score >= 80 else "C"

Operator Overloading

Python lets you define how operators behave on your own classes by implementing special dunder methods. This is how NumPy arrays support + and *, how Pandas DataFrames support ==, and how custom types integrate naturally with Python’s syntax.

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

    def __add__(self, other):
        # Called when you write v1 + v2
        return Vector(self.x + other.x, self.y + other.y)

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

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v1 + v2   # Vector(4, 6) — __add__ is called automatically

Key dunder methods for operators: __add__, __sub__, __mul__, __truediv__, __eq__, __lt__, __len__, __contains__.

Frequently Asked Questions

What is the walrus operator?
The walrus operator (:=) assigns a value and returns it in a single expression. It's useful in while loops and comprehensions to avoid computing the same value twice.
What's the difference between / and // in Python?
/ always returns a float (true division). // returns the floor (integer part) of the division — for example, 7 // 2 is 3.
How does Python's 'not in' operator work?
not in returns True if a value is not found in a sequence or collection. It works on strings, lists, tuples, sets, and dict keys.