Python Multiple Assignment: Syntax and Behavior
Python's multiple assignment evaluates the right side before assigning. This article covers variable swapping, iterable unpacking, star expressions, and common failure cases.
Python's multiple assignment lets you assign several variables in a single statement. The key to using it correctly is understanding that the right-hand side is evaluated before any assignment takes place, and that the resulting values are then unpacked into the targets on the left.
That evaluation order explains the common swap idiom, iterable unpacking, star expressions, and the failure modes in the examples below.
How Multiple Assignment Evaluates the Right Side First
When you write:
a, b = 1, 2
Python evaluates the right-hand side as an expression list, which produces the tuple (1, 2), and then unpacks it into a and b. The right-hand expression is evaluated before any assignment happens. That ordering matters for expressions that depend on the current values of the variables being assigned.
x = 1 y = 2 x, y = y, x
The right side y, x is evaluated first, producing (2, 1). Only then are the assignments performed. This is why the swap works without a temporary variable. If assignments happened left-to-right as they were written, x would be overwritten before y received its new value.
This evaluation order also applies when the right side contains function calls or expressions:
a, b = compute_a(), compute_b()
Both functions run before either variable is assigned. If compute_b depended on the new value of a, that dependency would not be visible inside the expression.
Swapping Variables Without a Temporary
The swap idiom is the most common use of multiple assignment in everyday code.
left = "first" right = "second" left, right = right, left
After this, left holds "second" and right holds "first". The temporary tuple on the right side holds both original values until the unpacking completes, so no data is lost.
This is more readable than the equivalent three-line version with an explicit temporary:
temp = left left = right right = temp
The multiple-assignment version communicates the intent directly and removes a variable that exists only to hold a value during the swap.
The same swap pattern works for any assignable targets, including list elements, because the right side is evaluated before any target is written:
items = [1, 2, 3, 4] items[0], items[1] = items[1], items[0]
After this, items is [2, 1, 3, 4].
Unpacking Sequences and Iterables
Multiple assignment is not limited to tuples. Any iterable of the matching length can be unpacked:
first, second = ["alpha", "beta"] x, y = (10, 20) key, value = {"name": "Ada"}.popitem()
The unpacking works on lists, tuples, strings, and any object that implements the iterator protocol. When the number of elements does not match the number of targets, Python raises a ValueError:
a, b = [1, 2, 3] # ValueError: too many values to unpack a, b, c = [1, 2] # ValueError: not enough values to unpack
This strictness is usually desirable because it surfaces mismatches early rather than silently dropping or padding data. When you intentionally want to ignore part of a sequence, the underscore convention is common:
first, _, last = [1, 2, 3]
The underscore is a regular variable name in Python, but by convention it signals that the value is not used.
Extended Unpacking With Star Expressions
Python 3 added extended unpacking, which lets one target collect the remaining elements:
head, *tail = [1, 2, 3, 4] # head = 1, tail = [2, 3, 4] *init, last = [1, 2, 3, 4] # init = [1, 2, 3], last = 4 first, *middle, last = [1, 2, 3, 4, 5] # first = 1, middle = [2, 3, 4], last = 5
The star target always collects a list, even when there is exactly one remaining element. Only one star expression is allowed per assignment statement:
a, *b, *c = [1, 2, 3] # SyntaxError
This pattern is useful when processing the first element of a sequence separately from the rest, such as parsing a command name and its arguments:
command, *args = user_input.split()
Where Multiple Assignment Breaks Down
The most common failure is a length mismatch, which raises ValueError. A subtler issue appears when the right side is a generator or another iterator that produces values lazily.
def generate(): yield 1 yield 2 yield 3 a, b = generate() # ValueError: too many values to unpack
Unpacking an iterator advances it while checking the count. If the iterator produces too many values, Python raises the error when it sees the first extra value, not after exhausting the whole iterator. In this example, the generator produces three values for two targets, so all three yields are consumed before the ValueError appears. If the generator has side effects, those side effects have already run before the exception is visible.
Runtime Cost and Readability Tradeoffs
Multiple assignment does add an unpacking step, but in normal Python code the cost is negligible. The more important consideration is readability and maintainability.
When the number of targets grows beyond three or four, the statement becomes harder to read:
a, b, c, d, e = get_five_values()
At that point, a named structure such as a dataclass or a NamedTuple communicates the meaning of each field better than positional unpacking. The reader no longer has to count positions to know what c represents.
Multiple assignment is most valuable when the structure is small, the order is meaningful, and the variable names make the intent clear:
status, message = api_response() latency_ms, error = measure_request(url)
When the number of values is large or the meaning is not obvious from position, prefer a named container. The unpacking syntax remains useful, but the data structure should carry the semantics.