Cheese icon

A List That Contains Itself

Author: guiferviz

Created:

Last Modified:

I have been writing recently about Having Fun With Python Chained Assignments, and it turns out there is a well-known variation of a chained assignments puzzle. In this Decode The Code, I am going to show a surprising way of creating a list that contains itself. It is always fun to work with self-referencing!

a = a[0] = [0]
print(a)  # Prints: [[...]]
assert a != [[...]]
assert a == [a]
assert a is a[0]

What is a = a[0] = [0] doing, and how is even possible for it to work?

Code Explained

The [[...]] is Python’s way of indicating that the list a contains itself. It is an expression we cannot directly write in code because three dots in Python represent an ellipsis data type object, not a reference to the outer object. Therefore, assert a != [[...]] even though print(a) outputs [[...]].

This line is surprising at first because in other languages like C or Java, assignments are made from right to left. With the first assignment being a[0] = [0], it seems impossible for the code to work, because a is not defined.

To solve this puzzle, we need to know How Chained Assignments Work In Python. The rightmost expression is evaluated first, so the list with [0] is created first. Then, this value is assigned to the targets a and a[0] in order, from left to right. That is the key to understanding this.

This means the code is actually equivalent to:

_rightmost_expr = [0]
a = _rightmost_expr
a[0] = _rightmost_expr

Note that introducing the _rightmost_expr variable is key here; otherwise, two different [0] in the code would lead to two different objects:

a = [0]
a[0] = [0]
assert a == [[0]]

Useful Link

This note is not going to be very extensive because I already found a really nice post about this example on susam.net - Peculiar Self-References. It contains a more extensive explanation and various interesting variations.