2010-08-27 3 views
6

Итак, я пытаюсь создать вложенный список в Python на основе ширины и высоты. Это то, что у меня есть до сих пор:Python - динамический вложенный список

width = 4 
    height = 5 
    row = [None]*width 
    map = [row]*height 

Теперь это явно не совсем верно. При печати он выглядит отлично:

[[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None], 
[None, None, None, None]] 

Но попытка присвоить значение позиции следующим образом:

map[2][3] = 'foo' 

я получаю:

[[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo'], 
[None, None, None, 'foo']] 

Очевидно, что это происходит потому, что каждый подсписок действительно просто ссылаясь на один и тот же объект, строку, так меняя одну, меняет их все. Так что это самое близкое, что у меня есть!

Как я могу динамически генерировать вложенный список? Благодаря!

+0

Пока не точная копия, см: http://stackoverflow.com/questions/1605024/python-using-the-multiply-operator-to -create-copy-of-objects-in-lists – carl

+2

'map()' - встроенная функция, это не рекомендуется переопределять. Найдите другое имя, при необходимости вы можете просто добавить '_'. –

ответ

11

Когда вы делаете [row]*height, вы получаете тот же объект списка в каждой строке. Ссылка на массив row повторяется в каждой строке, что означает, что каждая строка фактически указывает на один и тот же объект списка. Следовательно, изменение одной строки фактически изменяет все строки.

Посмотрите, что происходит, когда вы печатаете id() для каждой строки. Они все одинаковые!

>>> grid = [[None] * width] * height 
>>> [id(row) for row in grid] 
[148014860, 148014860, 148014860, 148014860, 148014860] 

Вы можете получить python для создания отдельных, но идентичных списков для каждой строки, используя понимание списка. Когда вы используете [rowexpr for i in xrange(height)], тогда rowexpr будет оцениваться один раз в строке. Трюк тогда заключается в том, чтобы использовать выражение, которое приведет к уникальному списку при каждом его вычислении.

Это будет иметь больше смысла, если вы видите его в действии:

>>> grid = [[None] * width for i in xrange(height)] 
>>> grid[2][3] = 'foo' 
>>> grid 
[[None, None, None, None], 
[None, None, None, None], 
[None, None, None, 'foo'], 
[None, None, None, None], 
[None, None, None, None]] 

Каждый раз, когда [None] * width оценивается она генерирует новый список.

>>> [id(row) for row in grid] 
[148016172, 148015212, 148016236, 148016108, 148016332] 
0

Я использую что-то вроде этого:

w = 5 
h = 5 

map = [] 

for i in range(h): 
row = [] 
for j in range(w): 
    row.append(None) 
map.append(row) 

print map 

map[2][3] = 'foo' 

print map 
+0

Понимание списка - это правильный путь для __one__. – aaronasterling

+0

Согласен, понимание списка чище, более читаемо, больше «Pythonic». Мой путь - это просто способ решить проблему, а также прочитать для людей (таких как я), которые все еще развиваются от C до python. – lalli

+0

Выполнение этого с помощью вложенных циклов не поможет вам или кому-либо другому перейти от C к python: он просто мешает. – aaronasterling

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