2010-02-16 1 views
9

Возможно, мне что-то не хватает о предполагаемом поведении списка, но почему происходит следующее:Расширение списка списков в Python?

x = [[],[]] 
y = [[]] * 2 

print x  # [[],[]] 
print y  # [[],[]] 
print x == y # True 

x[0].extend([1]) 
y[0].extend([1]) 

print x # [[1],[]], which is what I'd expect 
print y # [[1],[1]], wtf? 

Я бы предположил, что оператор * делает что-то неожиданное здесь, хотя я не совсем уверен, что. Кажется, что что-то происходит под капотом, что делает исходные x и y (до вызова продления) на самом деле не равными, хотя оператор == и repr оба выглядят так, как будто они были одинаковыми.

Я только натолкнулся на это, потому что хотел предварительно заполнить список пустых списков размера, определенного во время выполнения, а затем понял, что он не работает так, как я себе представлял. Я могу найти лучший способ сделать то же самое, но теперь мне любопытно, почему это не сработало. Это Python 2.5.2 BTW. У меня нет новой версии, поэтому, если это ошибка, я не уверен, что она уже исправлена.

+0

Я знаю, что добавляет, я только что придумал надуманный пример ради вопроса. –

ответ

16

В случае [something] * 2, python просто делает копию-копию. Поэтому, если закрытый тип (ы) изменчивы, их изменение будет отражено в любом месте ссылки на объект.

В вашем примере y[0] и y[1] указывают на тот же объект закрытого списка. Вы можете проверить это, выполнив y[0] is y[1] или поочередно id(y[0]) == id(y[1]).

Однако вы можете переназначить элементы списка, так что если вы сделали:

y[0] = [1] 

ты бы вновь связала первый элемент в новый список, содержащий элемент «1», и вы у вас есть ожидаемый результат.

Контейнеры в хранилищах питона хранят ссылки, и в большинстве контейнеров последовательностей можно ссылаться на один и тот же элемент несколько раз. Список может фактически ссылаться на себя как на элемент, хотя полезность этого ограничена.

Этот вопрос не пришел бы, если бы вы умножаются список, содержащий неизменные типы:

a = [0, 1] * 2 

выше даст вам список [0, 1, 0, 1] и действительно оба экземпляра 1 указывают на тот же объект, но поскольку они неизменяемы, вы не можете изменить значение объекта int, содержащего «1», только переназначить элементы.

Таким образом: a[1] = 5 приведет к a, отображающему [0, 5, 0, 1].

+0

Спасибо, это имеет смысл. –

4

Заявление y = [[]] * 2 связывает y со списком, содержащим 2 копии одного списка. Использование:

y = [[], []] 

или

y = [[] for n in range(2)] 
+4

Технически это две ссылки на один и тот же список, а не на копии. – Crast

+0

u означает «2 ссылки» вместо «2 копии», правильно?Я предложил это как редактирование – kmonsoor

1

y содержит две ссылки на один, изменчивый, список.