2015-12-09 3 views
3

Я думаю, что здесь очень странный код Python, но я не знаю причину:Почему поведение питона не соответствует ожиданиям

In [7]: a = [[]] * 3 

In [8]: b = [[], [], []] 

In [9]: a == b 
Out[9]: True 

In [10]: a[0].append(1) 

In [11]: b[0].append(1) 

In [12]: a == b 
Out[12]: False 

In [13]: a 
Out[13]: [[1], [1], [1]] 

In [14]: b 
Out[14]: [[1], [], []] 

Почему это [[1], [1], [1]] после a[0].append(1)?

Аналогичная проблема:

In [15]: c = dict.fromkeys(range(3),[]) 

In [16]: d = {0:[], 1:[], 2:[]} 

In [17]: c == d 
Out[17]: True 

In [18]: c[0].append(1) 

In [19]: d[0].append(1) 

In [20]: c == d 
Out[20]: False 

In [21]: c 
Out[21]: {0: [1], 1: [1], 2: [1]} 

In [22]: d 
Out[22]: {0: [1], 1: [], 2: []} 

В моей понимаю, a является b и c также равна d, но это не так. ЗАЧЕМ? Может кто-нибудь мне помочь? Огромное спасибо!

ответ

4

Первая версия:

>>> a = [[]] * 3 

создает список, содержащий три раза один и тот же список. Посмотрите идентификаторы элементов:

>>> [id(x) for x in a] 
[4454962120, 4454962120, 4454962120] 

В то время как это:

>>> b = [[], [], []] 

создает три списка:

>>> [id(x) for x in b] 
>>> [4454963720, 4455011592, 4454853448] 

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

>>> size = 100 
>>> long_list = [[] for x in range(size)] 

Теперь добавление к первому подсписком:

>>> long_list[0].append(10) 
>>> long_list[:10] 

изменения только первый суб-список:

>>> long_list[:10] 
[[10], [], [], [], [], [], [], [], [], []] 
+0

Спасибо! Например, если я хочу создать длинный список, например 'b', он будет содержать 100' [] 's. Очевидно, что 'b = [[], [], [], ...]' не является хорошим решением, как я могу его достичь? –

+0

Добавлен пример. –

2

[[]]*3 создает список из 3 ссылок на один и тот же список, в то время как [[],[],[]] создает список из 3 ссылок на 3 разных списка.

2

Для обоих a и c, вы создаете один пустой список, который ссылается 3 раза , Когда вы меняете его, все ссылки на него меняются. Для b и d вы создаете 3 отдельных пустых списков, которые полностью независимы.

Вы можете проверить, одинаковы ли два объекта с помощью оператора is, например. x is y. Вот то, что он показывает в первом примере:

>>> a = [[]] * 3 
>>> b = [[], [], []] 
>>> 
>>> a[0] is a[1] 
True 
>>> b[0] is b[1] 
False 
>>> 

И в вашем втором примере:

>>> c = dict.fromkeys(range(3), []) 
>>> d = {0:[], 1:[], 2:[]} 
>>> 
>>> c[0] is c[1] 
True 
>>> d[0] is d[1] 
False 
>>> 
0

В обоих случаях & с содержит 3 ссылок на один пустой список, но б & d содержат 3 пустые списки. Поэтому, когда вы сравниваете их 3 серии пустых == 3 лота пустых.

Когда добавление к первому элементу как в & с добавляемым к единому списку, что у Вас есть 3 ссылки на так что все три стали ссылками на [1], но в б & д добавляемой к первому из 3 перечисляет только то, что один изменяется.

С теми же определениями:

In [8]: a[0] is a[1] 
Out[8]: True 

In [9]: b[0] is b[1] 
Out[9]: False 
Смежные вопросы