Я нашел назначение a = a[1:] = [2] в статье. Я попробовал это в python3 и python2; все работает, но я не понимаю, как это работает. = здесь не похоже на C; C процессы = справа налево. Как python обрабатывает оператор =?
Почему цепное задание работает таким образом?
Ответ 1
Per языковые документы при назначении:
Оператор присваивания оценивает список выражений (помните, что это может быть одно выражение или список, разделенный запятыми, последний из которых имеет кортеж) и присваивает единственный результирующий объект каждому из целевых списков слева направо.
В этом случае a = a[1:] = [2] имеет список выражений [2] и два "целевых списка", a и a[1:], где a - самый левый список целей.
Вы можете видеть, как это происходит, глядя на разборку:
>>> import dis
>>> dis.dis('a = a[1:] = [2]')
1 0 LOAD_CONST 0 (2)
2 BUILD_LIST 1
4 DUP_TOP
6 STORE_NAME 0 (a)
8 LOAD_NAME 0 (a)
10 LOAD_CONST 1 (1)
12 LOAD_CONST 2 (None)
14 BUILD_SLICE 2
16 STORE_SUBSCR
18 LOAD_CONST 2 (None)
20 RETURN_VALUE
(Последние две строки разборки могут быть проигнорированы, dis делает оболочку функции для демонтажа строки)
Важно отметить, что когда вы выполняете x = y = some_val, some_val загружается в стек (в этом случае LOAD_CONST и BUILD_LIST), тогда запись стека дублируется и назначается из слева направо, до заданных целей.
Итак, когда вы это сделаете:
a = a[1:] = [2]
он делает две ссылки на новый list, содержащий 2, а первое действие - это STORE одна из этих ссылок на a. Затем он сохраняет вторую ссылку на a[1:], но так как назначение среза мутирует a, оно должно снова загрузить a, которое получает только list. К счастью, list устойчив к присваиванию self-slice, или у нас были бы проблемы (это было бы навсегда чтение значения, которое оно просто добавило, чтобы добавить в конец до тех пор, пока мы не исчерпали память и не разбились); как есть, он ведет себя так, как копия [2] была назначена для замены любого и всех элементов из индекса один дальше.
Конечный результат эквивалентен тому, что вы сделали:
_ = [2]
a = _
a[1:] = _
но он избегает использования имени _.
Чтобы быть понятным, демонтаж аннотируется:
Сделать список [2]:
1 0 LOAD_CONST 0 (2)
2 BUILD_LIST 1
Сделайте копию ссылки на [2]:
4 DUP_TOP
Выполнить хранилище до a:
6 STORE_NAME 0 (a)
Выполнить хранилище до a[1:]:
8 LOAD_NAME 0 (a)
10 LOAD_CONST 1 (1)
12 LOAD_CONST 2 (None)
14 BUILD_SLICE 2
16 STORE_SUBSCR
Ответ 2
То, как я понимаю такие назначения, состоит в том, что это эквивалентно
temp = [2]
a = temp
a[1:] = temp
Результирующее значение [2, 2] согласуется с этой интерпретацией.