Why this matters
So far you have bound one name at a time with name = value. Real code constantly updates values (count += 1), unpacks several results at once (quotient, remainder = divmod(a, b)), swaps values, and sometimes needs to capture a value in the middle of an expression. Python has compact, readable syntax for all of these. Each one is still just binding names to objects, and keeping that model in mind explains the one genuinely tricky case: += on a list that has another name.
Augmented assignment
Updating a name based on its own value is so common that Python has a shorthand for every arithmetic operator:
| Shorthand | Means (for immutable values) |
|---|---|
x += y | x = x + y |
x -= y | x = x - y |
x *= y | x = x * y |
x /= y | x = x / y |
x //= y | x = x // y |
x %= y | x = x % y |
x **= y | x = x ** y |
score = 0
score += 10
score += 5
score *= 2
print(score)
greeting = "Hello"
greeting += ", world"
print(greeting)
30
Hello, world
There is no ++ or -- in Python. x++ is a SyntaxError, and ++x is legal but means +(+x), which does nothing. Write x += 1.
Note that the name must already exist: total += 1 on a fresh name raises NameError: name 'total' is not defined, because Python must read the old value first. That is why accumulator code starts with total = 0.
What += really does: in-place where possible
For ints, floats, strings and tuples (immutable types), x += y computes a new object and rebinds x, exactly like x = x + y. But a type may define an in-place version of the operator. Lists do: += on a list extends the existing list object, then rebinds the name to that same object.
a = [1, 2]
b = a # alias
a += [3] # in place: mutates the shared list
print(a, b)
c = [1, 2]
d = c
c = c + [3] # builds a new list; only c is rebound
print(c, d)
[1, 2, 3] [1, 2, 3]
[1, 2, 3] [1, 2]
after a += [3]: after c = c + [3]:
a --\ c ----> [1, 2, 3] (new object)
>--> [1, 2, 3] d ----> [1, 2] (old object)
b --/
Underneath, a += [3] compiles to a BINARY_OP instruction with the in-place flag (+=), which calls the list's __iadd__ method if it has one, and falls back to __add__ otherwise. You will meet these "dunder" methods properly in the object-oriented module. For now, remember the rule: on mutable objects, augmented assignment may mutate; on immutable ones it always rebinds.
Multiple assignment and unpacking
You can bind several names in one statement by putting comma-separated names on the left:
x, y = 3, 4
print(x, y)
q, r = divmod(17, 5)
print(q, r)
3 4
3 2
The right side 3, 4 creates a tuple (an immutable sequence; the comma makes it, not parentheses). The left side unpacks it: the first item is bound to x, the second to y. The number of names must match the number of items:
a, b = 1, 2, 3
ValueError: too many values to unpack (expected 2)
Module 7 extends this with *rest patterns for collecting leftover items.
Swapping
Because the whole right-hand side is evaluated before any name is rebound, swapping needs no temporary variable:
a = "left"
b = "right"
a, b = b, a
print(a, b)
right left
Step by step: evaluate b, a, building the tuple ("right", "left") from the objects the names refer to now. Then bind a to the first element and b to the second. Compare the naive version:
a = b # a and b both refer to "right"; "left" has no name now
b = a # b refers to "right" again
That loses the original value of a, which is the bug in this lesson's swap exercise starter.
Chained assignment
x = y = 0 binds both names to the same object:
x = y = 0
x += 1
print(x, y)
1 0
With an immutable 0 that is harmless: x += 1 rebinds x. With a mutable object it means aliasing: after a = b = [], appending to a also changes what b shows. To get two separate lists, write a = [] and b = [] on separate lines.
The walrus operator :=
Ordinary assignment is a statement: it cannot appear inside an expression. Python 3.8 added the assignment expression name := value, nicknamed the walrus operator because := looks like a walrus lying on its side. It binds the name and produces the value, so the value can be used right away:
print((n := 10) * 2)
print(n)
20
10
The usual purpose is to avoid computing something twice or splitting a natural expression across lines. You will see its typical uses in the next module, with if and while:
if (size := len(text)) > 80:
print("too long by", size - 80)
while (line := input()) != "quit":
print("you said", line)
Rules: the walrus is not allowed as a bare statement (n := 5 alone is a SyntaxError; use n = 5), and it usually needs parentheses inside larger expressions. Use it sparingly: a separate assignment line is often clearer.
Evaluation order
In an assignment, Python evaluates the right-hand side first, then binds targets left to right. Within an expression, operands are evaluated left to right. These rules make every example in this lesson predictable:
i = 0
i, x = i + 1, i + 10 # right side uses the old i (0): (1, 10)
print(i, x)
1 10
Common mistakes
x++:SyntaxError: invalid syntax. Usex += 1.- Augmenting an undefined name:
NameError. Initialize first (count = 0). - Wrong number of names when unpacking:
ValueError: not enough values to unpack (expected 3, got 2)ortoo many values to unpack. - Shared mutable objects from chained assignment:
a = b = []gives one list with two names. - Expecting
+=on a list to leave aliases alone. It mutates the shared list.
Recap
x op= yupdatesx; for immutable types it isx = x op y, for mutable types like lists it may mutate in place.a, b = 1, 2packs a tuple on the right and unpacks it on the left; counts must match.a, b = b, aswaps, because the right side is fully evaluated before rebinding.x = y = valuebinds both names to the same object.(name := expr)binds and returns a value inside an expression; mostly used withifandwhile.
Going further: run import dis; dis.dis("a, b = b, a") to see how CPython swaps (it does not even build a tuple; it uses a stack SWAP). PEP 572 explains the motivation for the walrus operator.