Пожалуйста, объясните такое поведение словаря Python - PullRequest
1 голос
/ 20 июня 2020

Рассмотрим следующий код:

# Case 1
a = dict()
b = dict()

a = {'name': 'Bob'}
b['0'] = a 

print("Initial a: ", a)
print("Initial b:", b)
print("")

a['name']  = 'Lucy'
print("Intermediate a: ", a)
print("Intermediate b: ", b)
print("")

Мы получаем наш результат:

Initial a: {'name': 'Bob'}
Initial b: {'0': {'name': 'Bob'}} 

Intermediate a: {'name': 'Lucy'}
Intermediate b: {'0': {'name': 'Lucy'}}

Таким образом, при изменении значения 'a' изменяется и 'b'. Я считаю, что это связано с изменяемым символом словаря.

Теперь рассмотрим этот фрагмент:

# Case 2
a = dict()
b = dict()

a = {'name': 'Bob'}
b['0'] = a 

print("Initial a: ", a)
print("Initial b:", b)
print("")

a = dict()
print("Intermediate a: ", a)
print("Intermediate b", b)
print("")

Результат:

Initial a: {'name': 'Bob'}
Initial b: {'0': {'name': 'Bob'}} 

Intermediate a: {}
Intermediate b: {'0': {'name': 'Bob'}}

Почему не ' t промежуточное значение b становится пустым словарем для ключа 0 для # case 2?

Ответы [ 5 ]

2 голосов
/ 20 июня 2020

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

Для меня более удивительно, как Bob превращается в Lucy во втором фрагменте. : -D

1 голос
/ 20 июня 2020

Вот иллюстрация из Python сеанса REPL.

In [1]: a = {1: 2}       # A couple of dicts similar to your example.
In [2]: b = {0: a}

In [3]: id(a)            # Every object in a Python program has a unique ID.
Out[3]: 4442001056

In [4]: id(b[0])         # Note that both `a` and `b[0]` refer to the same object.
Out[4]: 4442001056

                         # Variable names are like labels. You can attach multiple
                         # labels to the same underlying object. We already have
                         # two ways to refer to object 4442001056: using `a` or `b[0]`.

In [5]: x = a            # Let's add another way.
In [6]: id(x)            # Again it's the same underlying object.
Out[6]: 4442001056

In [7]: a[77] = 77       # Let's modify object 4442001056 in various ways.
In [8]: b[0][88] = 88
In [9]: x[99] = 99

                         # The changes are reflected everywhere.

In [10]: a
Out[10]: {1: 2, 77: 77, 88: 88, 99: 99}

In [11]: b
Out[11]: {0: {1: 2, 77: 77, 88: 88, 99: 99}}

In [12]: x
Out[12]: {1: 2, 77: 77, 88: 88, 99: 99}

                         # Now let's attach the label `a` to a different object --
                         # in this case object 4427016088.

In [13]: a = {'hello': 'world'}
In [14]: id(a)
Out[14]: 4427016088

                         # Nothing happens to object 4442001056.

In [15]: b
Out[15]: {0: {1: 2, 77: 77, 88: 88, 99: 99}}

In [16]: x
Out[16]: {1: 2, 77: 77, 88: 88, 99: 99}

Также см. Статью Неда Батчелдера о Python именах и значениях .

1 голос
/ 20 июня 2020

В первом случае «a» и b ['0'] указывают на один и тот же адрес памяти, поэтому, когда вы вносите изменения в «a», это также влияет на b [«0»]. Во втором случае, когда вы назначаете новый словарь в переменную «a», вы не перезаписываете адрес памяти, в котором находится старый словарь (также обозначенный b [0]). Переменная a теперь указывает на новый адрес памяти, который содержит новый словарь, старый, если на него не указывает никакая переменная, будет удален из памяти, но на него указывает b [0], остается неизменным

1 голос
/ 20 июня 2020

Думаю, доктор. v ответил на ваш вопрос, но дополнительная информация - если вы хотите легко скопировать объект в python, вы можете использовать copy встроенный модуль:

from copy import deepcopy

a = {'hamed': 12, 'dr.v': 20}
b = deepcopy(a)
a['new'] = 'is this in b too?'
print(f'a is ({a}) b is ({b})

и вывод is:

a is ({'hamed': 12, 'dr.v': 20, 'new': 'это тоже в b?'}) b is ({'hamed' : 12, 'dr.v': 20})

0 голосов
/ 20 июня 2020

Я рекомендую вам проверить код, используя http://www.pythontutor.com/

, вы увидите, что, создав a новый dict в случае # 2 python сохраняет текущий указатель b находится в том же месте памяти, но выделяет a в новое место в памяти, поскольку b все еще указывает на старую ячейку памяти, при изменении a это не влияет на b.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...