2010-09-03 2 views
7

Когда я исполняю (я использую интерактивную оболочку) эти заявления я получаю это:В чем разница между LIST.append (1) и LIST = LIST + [1] (Python)

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

Уточнение на все это было бы весьма полезным.

Благодаря

+0

'+ =' странно в питоне. например, 'a = (1, 2); a + = (2,) 'дает' (1, 2, 3) '! Это полная противоположность ситуации в списке, где ite изменяет список на месте. Невозможно изменить кортеж на месте.поэтому многие люди предпочитают всегда использовать форму 'a = a + b'. – aaronasterling

+0

нет, нет, после a = (1, 2); a + = (2,) a есть (1,2,2), что странно в этом? – Kugel

+0

Я думаю, он имел в виду 'a + = (3,)'. И это странно, что он позволяет вам изменять (неизменный) кортеж на месте, как это. – efritz

ответ

2

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

Я не уверен в поведении +=.

+0

'+ =', похоже, ведет себя как 'append' (я только что протестировал его) –

+1

@Andre, nope. Он ведет себя как 'extend'. – habnabit

+0

вы правы '+ = 5' не работал .. –

15
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 
+0

@Aaron Да, вы правы. Исправлена. –

0

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

+0

Итак, когда я назначаю переменную списку, она получает ссылку на объект? Это потому, что фактически список - это не список, а ссылка? Думаю, сейчас я понимаю. Это может произойти со списком и словарем? Потому что они на самом деле являются как ссылками на сам объект. Благодарю вас за разъяснение. То, что я прочитал где-то еще, было всего лишь вауге и на самом деле не говорило, что использование оператора + вызвало список .__ add__ Thanks (^_^) – aitee

+0

У вас есть мысли о + =? – aitee

+0

Не только 'list' и' dict', * все * в Python - это объект. Все объекты хранятся в куче, и все переменные являются просто ссылками. Но некоторые объекты неизменяемы (например, 'int' и 'string'), а некоторые неизменяемые объекты интернированы, поэтому вы не получаете этого загадочного поведения. Вы должны различать модификацию данных и изменение сопоставления между именами переменных и данными. Последнее - это то, что происходит, когда вы присваиваете что-то переменной. Обратите внимание, однако, что само отображение переменной может быть частью данных, если оно представляет элементы объекта. – rkhayrov

1

Если Вам интересно о байткодах:

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

Наиболее интересным является форма '+ ='. – aaronasterling

+0

Хотя я не новичок в программировании, я довольно новичок в python. Это (байт-коды) не имеет для меня большого смысла. Не являются ли байт-коды обычно кодами, которые ниже уровня, чем язык, который ближе к машинным кодам и быстрее запускается? Возможно, я получил неправильное определение. – aitee

+0

@aaronasterling: интересно! Добавлен. @aitee: Да, они есть. 'dis' выводит« хорошее »представление байт-кодов, с которыми компилируется функция Python. Это часто полезно для того, чтобы видеть, что происходит «под капотом». – katrielalex

Смежные вопросы