Python - обновить словарь самостоятельного класса внутри функции класса

У меня есть словарь, объявляющий в классе (self.d1). После вызова функции f1, self.d1 нужно обновить до локального dict объявить внутри f1

import copy
class num:
 def __init__(self):
 self.d1 = {'a':1, 'b':2, 'c':3}
 self.f1(self.d1)
 print self.d1
 def f1(self,d):
 d2 = {'d':4, 'e':5, 'f':6}
 d = copy.deepcopy(d2)
test = num()

Я ожидаю, что вывод будет:

{'d':4, 'e':5, 'f':6}

но выход

{'a':1, 'b':2, 'c':3}

Я хочу понять, в чем проблема, а не только решение

4 ответа

Вы не хотите назначать d в f1(), так как он теряет старую привязку, которую он должен был self.d1. Поэтому после назначения d является только локальной переменной f1().

Но вы можете достичь того, чего хотите:

class num:
 def __init__(self):
 self.d1 = {'a':1, 'b':2, 'c':3}
 self.f1(self.d1)
 print self.d1
 def f1(self,d):
 d2 = {'d':4, 'e':5, 'f':6}
 d.clear()
 d.update(d2)
test = num()

Выход

{'e': 5, 'd': 4, 'f': 6}

Обратите внимание, что мой код не присваивает d в f1(), он делает только вызовы, которые мутируют существующий объект.

Для дополнительной справки по этой и смежным темам см. эту замечательную статью SO stalwart, Ned Batchelder: Факты и мифы о именах и значениях Python


Проблема заключается в том, что

d = deepcopy(...)

Вы не изменяете словарь, на который ссылается d, вы просто изменяете d, чтобы ссылаться на другой словарь (в данном случае на вновь созданную копию словаря).


Если вы присваиваете значение {'a' : 1} некоторой переменной self.d1, то эта переменная сохраняет ссылку на значение. Это означает, что вы можете изменить значения d1, обратившись к нему, например: self.d1['a'] = 2, и теперь значение будет {'a' : 2'}.

Вы также можете изменить ссылку переменной self.d1, присвоив ее чему-то новому. Поэтому в вашей функции f1 вы фактически изменяете ссылку, на которую указывает d, а не значение, на которое она ссылается. И из-за определения функции self.d1 по-прежнему будет ссылаться на исходное значение вне области действия.


Дайте другое объяснение...

class num:
 def __init__(self):
 self.d1 = {'a':1, 'b':2, 'c':3}
 # calling a function with a dictionary copies the *reference* to the
 # dictionary object.
 print 'first test ..'
 self.test_dict_arg_1(self.d1)
 print self.d1
 print 'second test ...'
 self.test_dict_arg_2(self.d1)
 print self.d1
 def test_dict_arg_1(self, d):
 d2 = {'d':4, 'e':5, 'f':6}
 # now you load d with a new value, the referenced object is untouched
 d = d2
 def test_dict_arg_2(self, d):
 d2 = {'d':4, 'e':5, 'f':6}
 # now you work with the referenced object
 d.clear()
 d.update(d2)

licensed under cc by-sa 3.0 with attribution.