2015-08-07 5 views
2

Для жизни меня я не могу понять, почему происходит следующее:Для перебираем словарей в списке (Python 2.7.6)

x = 2 
y = [] 
z = { "player" : 0, "name": "none", "fired": 0, "hits": 0, "misses": 0, "streak": 0, "longest streak": 0 } 

def number_player(x, y, z): 
    for i in range(x): 
     y.append(z) 
     y[i]["player"] = (i + 1) 

number_player(x, y, z) 
print y 

Консоль возвращает это:

[{'streak': 0, 'hits': 0, 'name': 'none', 'player': 2, 'misses': 0, 'longest streak': 0, 'fired': 0}, {'streak': 0, 'hits': 0, 'name': 'none', 'player': 2, 'misses': 0, 'longest streak': 0, 'fired': 0}] 

Таким образом, в short, он создает пару ключей/значений {... "player": "2" ...} дважды. Если я запрошу печать в конце каждого цикла, первый возвращаемый словарь в списке содержит пару пар {... "player": "1" ...} ключей/значений, как ожидалось.

Незнакомец мне еще в том, что если я прохожу:

x = 3 
y = [{ "player" : 0, "name": "none", "fired": 0, "hits": 0, "misses": 0, "streak": 0, "longest streak": 0 }] 

затем запустить цикл так, он добавляет еще два словаря, цикл работает отлично над первым, затем дублирует значения двух последних. Я предполагаю, что здесь лежит причина и решимость, хотя я слишком новичок в этом, чтобы понять их из проблемы.

Ваша помощь в том, чтобы понять, почему это происходит, было бы весьма полезно.

Спасибо

+3

Вы заполняете 'y' ** ссылками на тот же словарь **. Не делай этого. – jonrsharpe

ответ

3

Причина вашей путаницы является линией y.append(z).

Это не добавляет копию словаря z, а скорее другую ссылку на тот же экземпляр z.

Поэтому в последней итерации цикла при изменении словаря, который вы только что добавили, вы также модифицируете первый словарь, который вы добавили в предыдущую итерацию. Ваш список y действительно выглядит просто как [z, z].

>>> print y 
[{'streak': 0, 'hits': 0, 'name': 'none', 'player': 2, 'misses': 0, 'longest streak': 0, 'fired': 0}, {'streak': 0, 'hits': 0, 'name': 'none', 'player': 2, 'misses': 0, 'longest streak': 0, 'fired': 0}] 
>>> y[0] 
{'fired': 0, 
'hits': 0, 
'longest streak': 0, 
'misses': 0, 
'name': 'none', 
'player': 2, 
'streak': 0} 
>>> y[0] is y[1] 
True 
>>> y[0]['player'] = 123 
>>> y[1]['player'] 
123 

Более вещий способ создания структуры будет со списком понимания:

>>> def new_player(n, name="none"): 
...  return {"player" : n, "name": name, "fired": 0, "hits": 0, "misses": 0, "streak": 0, "longest streak": 0} 
... 
>>> y = [new_player(n) for n in range(2)] 
>>> y 
[{'fired': 0, 
    'hits': 0, 
    'longest streak': 0, 
    'misses': 0, 
    'name': 'none', 
    'player': 0, 
    'streak': 0}, 
{'fired': 0, 
    'hits': 0, 
    'longest streak': 0, 
    'misses': 0, 
    'name': 'none', 
    'player': 1, 
    'streak': 0}] 
+0

Большое спасибо за объяснение и за дальнейшую демонстрацию понимания списка. Моя ошибка в логике предполагала, что это действительно просто копирование значения переменной, а не копирование самой переменной. – JJA

1

, как другие указали вы Добавляя ссылку на тот же dictionairy

использование DeepCopy из модуль копирования.

import copy 

x = 2 
y = [] 
z = { "player" : 0, "name": "none", "fired": 0, "hits": 0, "misses": 0, "streak": 0, "longest streak": 0 } 

def number_player(x, y, z): 
    for i in range(x): 
     y.append(copy.deepcopy(z)) 
     y[i]["player"] = (i + 1) 

number_player(x, y, z) 
print y 
+0

Хотя 'copy.deepcopy()' *** *** необходим для общего случая, метод 'dict.copy()' здесь адекватен, потому что все значения являются простыми неизменяемыми типами - 'int' и 'str 's. –

+0

Я по-настоящему ценю ваш ответ и добавление меня к модулю копирования. Если мои подсчет голосов подсчитали за что угодно, у вас будет хотя бы один. Спасибо. – JJA

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