Search code examples
pythonvariable-assignmentinfinite-loop

Chain assignment in Python for list


I am trying to understand chain assignment in Python.

If I run x = x[1] = [1, 2], I get an infinite list [1, [...]].

But if I run x = x[1:] = [1, 2], I will get a normal list [1, 1, 2].

How does it work in the background to make these two different results?


Solution

  • First, understand that in a chained assignment, the right-most expression is evaluated to an object. A reference to that object is then assigned to each target in sequence, from left to right. x = y = z is effectively the same as

    t = z # A new temporary variable "t" to hold the result of evaluating z
    x = t
    y = t
    del t
    

    Second, you need to understand the difference between assigning t to the subscription x[1] and to the slicing x[1:]. In the former, element 1 of x is replaced by t. In the latter, elements x[1], x[2], etc are replaced by t[0], t[1], etc, extending or shrinking x as necessary.

    The first example is equivalent to

    t = [1,2]
    x = t
    x[1] = t
    del t
    

    x[1] becomes a reference to x itself; list.__repr__ can detect cycles like this and represents them with .... x, x[1], x[1][1], etc are all references to the original list [1,2].

    The second example is equivalent to

    t = [1,2]
    x = t
    x[1:] = t
    del t
    

    In this case, no cycles are created. x[1] is replaced by a reference to 1, not x/t itself, and x is extended to make x[2] a reference to 2. (If it helps, think of x[1:] = t as producing the same result as x = [x[0]]; x.extend(t).)