Я нашел назначение 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]
согласуется с этой интерпретацией.