1

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?

sn_2022
  • 13
  • 3

3 Answers3

3

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).)

chepner
  • 497,756
  • 71
  • 530
  • 681
0
x = x[1] = [1, 2]

In this case, x and x[1] are the same object. Therefore x contains itself, which is represented by ... in your output.

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

In this case, x is a slice, and slices are copies. so they are not the same object.

John Gordon
  • 29,573
  • 7
  • 33
  • 58
  • 1
    This is a slice *assignment*, though. Basically `x = [1,2]` is performed first, then the slice assignment assigns `1` to `x[1]` and appends `2` to `x` ("assigning" 2 to `x[2]`). – chepner Nov 29 '22 at 21:28
0

Explaining the outputs:

x = x[1] = [1, 2] # Output: [1, [...]]

The reason is that the list is not copied, but referenced.

  • x[1] is a reference to the list [1, 2].
  • When you assign x[1] to x, you are assigning a reference to the list [1, 2] to x.
  • So x and x[1] are both references to the same list.
  • When you change the list through one of the references, the change appears in the other reference as well. This is called aliasing.

x = x[1:] = [1, 2] # Output: [1, 1, 2]

The reason is that the list is copied, not referenced.

  • x[1:] is slice of the list [1, 2].
  • The slice is a copy of the list, not a reference to the list. When you assign x[1:] to x, you are assigning a copy of the list [1, 2] to x.
  • So x and x[1:] are both copies of the same list.
  • When you change the list through one of the references, the change does not appear in the other reference.
Jiya
  • 745
  • 8
  • 19