В чем разница между LIST.append (1) и LIST = LIST + [1] (Python) - PullRequest
8 голосов
/ 03 сентября 2010

Когда я выполняю (я использую интерактивную оболочку) эти операторы, я получаю следующее:

L=[1,2,3]
K=L

L.append(4)

L
[1,2,3,4]
K
[1,2,3,4]

Но когда я делаю то же самое, заменяя L.append (4) на L = L + [4] Я получаю:

L
[1,2,3,4]
K
[1,2,3]

Это какая-то ссылка? Почему это происходит?

Еще одна забавная вещь, которую я заметил, это то, что L + = [4] действует как .append, что странно, так как я думал, что будет действовать как L = L + [4].

Разъяснение всего этого будет высоко оценено.

Спасибо

Ответы [ 4 ]

16 голосов
/ 03 сентября 2010
L.append(4)

Добавляет элемент в конец существующего списка L.

L += [4]

Оператор += вызывает магический метод __iadd__(). Оказывается, list переопределяет метод __iadd__() и делает его эквивалентным extend(), который, подобно append(), добавляет элементы непосредственно в существующий список.

L = L + [4]

L + [4] генерирует новый список, равный L с 4, добавленными в конец. Этот новый список затем возвращается на L. Поскольку вы создали новый объект списка, K не изменяется этим назначением.

Мы можем использовать id(), чтобы определить, когда создается новая ссылка на объект:

>>> L = [1, 2, 3]
>>> id(L)
152678284
>>> L.append(4)
>>> id(L)
152678284

>>> L = [1, 2, 3]
>>> id(L)
152680524
>>> L = L + [4]
>>> id(L)
152678316
2 голосов
/ 03 сентября 2010

С append вы изменяете список напрямую. С L=L+[4] вы делаете копию оригинального L и добавляете новый элемент, затем присваиваете результат обратно L и нарушаете его эквивалентность K.

Я не уверен насчет поведения +=.

1 голос
/ 03 сентября 2010

Если вам интересно узнать о байт-кодах:

>>> def L_app( ):
...     L.append( 4 )
...
>>> def L_add( ):
...     L = L + [ 4 ]
...
>>> def L_add_inplace( ):
...     L += [ 4 ]
...
>>> dis.dis( L_app )
  2           0 LOAD_GLOBAL              0 (L)
              3 LOAD_ATTR                1 (append)
              6 LOAD_CONST               1 (4)
              9 CALL_FUNCTION            1
             12 POP_TOP
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
>>> dis.dis( L_add )
  2           0 LOAD_FAST                0 (L)
              3 LOAD_CONST               1 (4)
              6 BUILD_LIST               1
              9 BINARY_ADD
             10 STORE_FAST               0 (L)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
>>> dis.dis( L_add_inplace )
  2           0 LOAD_FAST                0 (L)
              3 LOAD_CONST               1 (4)
              6 BUILD_LIST               1
              9 INPLACE_ADD
             10 STORE_FAST               0 (L)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE
0 голосов
/ 03 сентября 2010

В вашем первом примере имена переменных K и L относятся к одному и тому же объекту, поэтому, когда вы вызываете метод, изменяющий этот объект, изменения, очевидно, видны через обе ссылки. Во втором примере оператор + вызывает list.__add__, который возвращает новый объект (объединение двух списков), а имя L теперь относится к этому новому объекту, тогда как K не повреждено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...