Skip to content

Expressions

An expression is any piece of code that produces a value. In Python, almost everything you write is either a statement (does something) or an expression (produces a value). Sometimes expressions are statements — f() is a valid statement.


Atoms — The Simplest Expressions

Atoms are the simplest building blocks:

Atom Examples
Identifiers x, my_variable, print
Literals 42, 3.14, "hello", b"bytes", True, None
Parenthesized expressions (1 + 2)
Tuple display (1, 2, 3) or 1, 2, 3
List display [1, 2, 3], [x**2 for x in range(5)]
Set display {1, 2, 3}, {x for x in range(5)}
Dict display {"a": 1}, {k: v for k, v in items}
Generator expression (x**2 for x in range(5))
... (Ellipsis) Used as a placeholder or in type hints
yield Only valid in a generator function

Attribute Access

# obj.attr
"hello".upper      # attribute lookup
[1,2,3].append     # method lookup
import os
os.path.join       # chained attribute lookup

Subscript / Indexing

my_list[0]         # integer index
my_dict["key"]     # dict key
my_str[1:5]        # slice
my_tensor[0, 1, 2] # multiple indices (numpy-style)

Python calls __getitem__ for indexing. Slices call __getitem__ with a slice object.


Calls

# Function call
print("hello")

# Method call
"hello".upper()

# With *args and **kwargs unpacking
def f(a, b, c): ...
args = (1, 2, 3)
f(*args)           # same as f(1, 2, 3)

kwargs = {"a": 1, "b": 2, "c": 3}
f(**kwargs)        # same as f(a=1, b=2, c=3)

Arithmetic Operators

5 + 2    # 7  — addition
5 - 2    # 3  — subtraction
5 * 2    # 10 — multiplication
5 / 2    # 2.5 — true division (always float)
5 // 2   # 2  — floor division (rounds toward -infinity)
5 % 2    # 1  — modulo
5 ** 2   # 25 — exponentiation
-5 // 2  # -3 — floor division rounds toward -infinity, NOT toward 0

// rounds toward negative infinity

7 // 2 is 3, but -7 // 2 is -4 (not -3). If you want truncation toward zero, use int(a / b) or math.trunc(a / b).


Bitwise Operators

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

a & b   # 0b1000 = 8  — AND
a | b   # 0b1110 = 14 — OR
a ^ b   # 0b0110 = 6  — XOR
~a      # -11          — NOT (two's complement)
a << 1  # 0b10100 = 20 — left shift
a >> 1  # 0b0101 = 5  — right shift

Comparison Operators

x == y   # equal
x != y   # not equal
x < y    # less than
x > y    # greater than
x <= y   # less than or equal
x >= y   # greater than or equal
x is y   # same object identity
x is not y
x in y   # x is a member of y
x not in y

Comparisons can be chained: 0 < x < 10 is equivalent to 0 < x and x < 10.


Boolean Operators

and and or are short-circuit operators and return an operand, not necessarily True or False:

# 'and' returns the first falsy value, or the last value if all are truthy
print(0 and "hello")   # 0    (short-circuits at 0)
print(1 and "hello")   # "hello" (both truthy, returns last)

# 'or' returns the first truthy value, or the last value if all are falsy
print(0 or "hello")    # "hello"
print("" or 0 or None) # None (all falsy, returns last)

# Practical idiom: default value
username = user_input or "Guest"

Conditional Expression (Ternary)

# value_if_true if condition else value_if_false
x = 10
label = "even" if x % 2 == 0 else "odd"
print(label)  # even

Lambda Expressions

Anonymous functions defined with lambda:

square = lambda x: x ** 2
add = lambda x, y: x + y

# Most useful as callbacks
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort(key=lambda x: -x)   # sort descending
print(numbers)   # [9, 5, 4, 3, 1, 1]

Lambda is limited to a single expression. For anything more complex, use a named def.


Assignment Expressions (Walrus :=) — Python 3.8+

:= assigns a value to a name as part of an expression:

# Without walrus — must call function twice or use temp variable
data = get_data()
if data:
    process(data)

# With walrus — cleaner
if data := get_data():
    process(data)

# Very useful in while loops
while chunk := file.read(8192):
    process(chunk)

See the Walrus Operator guide for detailed usage.


Starred Expressions

* unpacks iterables and ** unpacks dicts in expressions:

a = [1, 2, 3]
b = [4, 5, 6]

combined = [*a, *b]         # [1, 2, 3, 4, 5, 6]
d1 = {"x": 1}
d2 = {"y": 2}
merged = {**d1, **d2}       # {"x": 1, "y": 2}

first, *rest = [1, 2, 3, 4]  # first=1, rest=[2,3,4]

Operator Precedence (Highest to Lowest)

Operators Description
(...), [...], {...} Parentheses, brackets
x[i], x[i:j], f(args), x.attr Subscript, call, attribute
await x Await expression
** Exponentiation
+x, -x, ~x Unary plus, minus, bitwise NOT
*, @, /, //, % Multiplication, matrix multiply, division
+, - Addition, subtraction
<<, >> Bit shifts
& Bitwise AND
^ Bitwise XOR
\| Bitwise OR
in, not in, is, is not, <, <=, >, >=, !=, == Comparisons
not x Boolean NOT
and Boolean AND
or Boolean OR
if – else Conditional expression
lambda Lambda
:= Walrus (assignment expression)