Вопрос:

словарь Python внутри / снаружи цикла

python python-3.x python-2.7

598 просмотра

6 ответа

13 Репутация автора

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

#ALL aliens get changed when I put put the dictionary up here
new_alien = {'colour': 'green'}

aliens=[]

for alien_number in range(3):
    #if i put new_alien here only one alien dictionary gets changed in the for loop (correct code)
    #new_alien = {'colour': 'green'}
    aliens.append(new_alien)

print(aliens)

for alien in aliens[0:1]:
    if (alien['colour'] == 'green'):
        alien['colour'] = 'yellow'

print(aliens[0:2])

Выведите, если new_alienвне цикла:

[{'colour': 'green'}, {'colour': 'green'}, {'colour': 'green'}]
[{'colour': 'yellow'}, {'colour': 'yellow'}]

Выведите, если new_alienвнутри цикла:

[{'colour': 'green'}, {'colour': 'green'}, {'colour': 'green'}]
[{'colour': 'yellow'}, {'colour': 'green'}]

Обратите внимание, что за пределами цикла ВСЕ чужой словарь: цвет меняется на желтый. Любое объяснение будет оценено. Спасибо!

Автор: SlowSloth Источник Размещён: 02.01.2018 04:35

Ответы (6)


1 плюс

81 Репутация автора

Python Tutor - это онлайн-приложение, которое показывает вам, что происходит. Вы можете вставить в него свой код и посмотреть, как интерпретатор Python выполняет код.

Вот объяснение в виде простого текста.

Следующее утверждение создает новый объект dict, а new_alien является просто ссылкой на объект dict.

new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}

Если вы поместите оператор this вне цикла, все элементы в списке ссылаются на один и тот же объект dict (или на то же пространство памяти), поскольку вы не создаете новый для каждого элемента.

Автор: laven_qa Размещён: 02.01.2018 04:43

1 плюс

12246 Репутация автора

Решение

Если вы надеваете new_alienнаружу, вы добавляете один и тот же объект снова и снова. Вы можете распечатать идентификатор объекта, id()чтобы увидеть, что я имею в виду здесь:

new_alien внутри цикла:

for alien_number in range(3): 
    new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}
    print(id(new_alien))
    aliens.append(new_alien)

Который выводит разные идентификаторы объектов:

1577811864456
1577811864528
1577811864960

Поэтому вы каждый раз добавляете новый объект. Разные ссылки на new_alien3 отдельных объекта. Если вы измените один объект, здесь будет изменен только один объект. Это правильный способ сделать это.

new_alien вне цикла:

new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}

for alien_number in range(3):
    print(id(new_alien))
    aliens.append(new_alien)

Вы получаете те же личности:

2763267730312
2763267730312
2763267730312

Это означает, что вы добавляете один и тот же объект снова и снова. Это означает, что если вы измените один объект, все объекты будут изменены. Это потому, что все они являются ссылками на один объект. Не путь, если вы хотите изменить их в будущем.

Автор: RoadRunner Размещён: 02.01.2018 04:48

0 плюса

761 Репутация автора

Объект в Python рассматривается как адрес в памяти под капотом. Таким образом, имя переменной для объекта - это просто ссылка на место в памяти компьютера, где хранится этот объект. Если вы запустите эту строку кода:

new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}

это создает объект в памяти, на который может ссылаться переменная new_alien. Если эта строка находится вне цикла, она запускается ОДИН РАЗ, а если она находится внутри цикла, она запускается несколько раз. Когда эта строка запускается несколько раз, это означает, что в памяти создается несколько объектов, но когда она запускается один раз, в памяти создается только один объект, и поэтому все они обновляются, когда он объявляется снаружи; потому что все они ссылаются на одну и ту же область памяти под капотом.

Автор: mark_maker Размещён: 02.01.2018 04:56

1 плюс

995 Репутация автора

Случай 1: Итак, когда вы append new_alien = {'colour': 'green', 'points': 5, 'speed': 'slow'}в списке, это относится к той же objectпамяти. Вы можете проверить ссылку на память по id(Your_Object_Name). В основном это работает как глобальная переменная.

Случай 2: когда вы пытаетесь append объявить внутри цикла, он создает другой объект с другой ссылкой на память.

Автор: R.A.Munna Размещён: 02.01.2018 04:58

1 плюс

5004 Репутация автора

Если вы поместите его снаружи, вы добавляете тот же new_alienобъект в aliensсловарь. Если вы поместите его внутрь, вы создадите 3 разных new_alienобъекта, а затем добавите его aliens.

for loop (correct code)
    new_alien = {'colour': 'green'}<-create a new dictionary {"c": "g"} and put it 
                                     under the name new_alien
    aliens.append(new_alien) # add the new dictionary

Хотя все они добавляют одну и ту же переменную new_alien, привязка к new_alienней различна в каждом цикле цикла. Каждый раз, когда у вас есть оператор присваивания new_alien, например new_alien = {'colour': 'green'}, вы (повторно) привязываетесь new_alienк вновь созданному словарю. Таким образом, когда позже вы измените один aliens, это не повлияет на других.


В то время как на другом случае: new_alien = {'colour': 'green'}это за пределами контура, то же ссылка на объект вставляется в словарь в 3 раза. В то время как вы изменили один из них на "yellow", вы измените только один. (На самом деле есть только один, который вы можете изменить, даже если он выглядит так, как будто их три.) Однако, пока вы печатаете его, вы также печатаете один и тот же словарь, сохраненный в 3 раза! Вот почему он дает вам тот же результат.


Вынос :

  • Объект может иметь разные имена, которые все ссылаются на него.
  • Имя переменной может ссылаться на разные объекты в разные моменты.

В первом случае new_alienссылается на другой объект словаря, в то время как цикл выполняется на каждом шаге.

В последнем случае, new_alienнаходится вне цикла, мы можем видеть , что aliens[0], aliens[1]и aliens[2]все они относятся к одной и тому же объекту словаря. Вы меняете один из них, да, только один объект изменяется. Вы меняете два из них; Тем не менее, один и тот же словарь изменен. Вы читаете все три; Вы просто читаете один и тот же словарь три раза.

Автор: Tai Размещён: 02.01.2018 05:07

0 плюса

0 Репутация автора

Это называется мелкой копией. Когда вы добавляете этот элемент, вы фактически добавляете тот же объект, и когда вы что-либо изменяете к нему, это влияет на основной объект:

Решение :

Вы [co / sho] будете использовать Deepcopy:

from copy import deepcopy
#ALL aliens get changed when I put put the dictionary up here
new_alien = {'colour': 'green'}

aliens=[]

for alien_number in range(3):
    #if i put new_alien here only one alien dictionary gets changed in the for loop (correct code)
    #new_alien = {'colour': 'green'}
    aliens.append(deepcopy(new_alien))


for alien in aliens[0:1]:
    if (alien['colour'] == 'green'):
        alien['colour'] = 'yellow'

print(aliens[0:2])
print(new_alien)

выход:

{'colour': 'green'}
[{'colour': 'yellow'}, {'colour': 'green'}]
{'colour': 'green'}
Автор: user9158931 Размещён: 02.01.2018 04:54
Вопросы из категории :
32x32