Я недавно боролся с ошибкой в Python. Это была одна из тех глупых ошибок новичка, но она заставила меня задуматься о механизмах Python (я долгое время программист на C ++, новичок в Python). Я выложу код ошибки и объясню, что я сделал, чтобы исправить это, а затем у меня есть пара вопросов ...
Сценарий: у меня есть класс с именем A, в котором есть член данных словаря, ниже приведен код (это, конечно, упрощение):
class A:
dict1={}
def add_stuff_to_1(self, k, v):
self.dict1[k]=v
def print_stuff(self):
print(self.dict1)
Класс, использующий этот код, является классом B:
class B:
def do_something_with_a1(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('a', 1)
a_instance.add_stuff_to_1('b', 2)
a_instance.print_stuff()
def do_something_with_a2(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('c', 1)
a_instance.add_stuff_to_1('d', 2)
a_instance.print_stuff()
def do_something_with_a3(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('e', 1)
a_instance.add_stuff_to_1('f', 2)
a_instance.print_stuff()
def __init__(self):
self.do_something_with_a1()
print("---")
self.do_something_with_a2()
print("---")
self.do_something_with_a3()
Обратите внимание, что каждый вызов do_something_with_aX()
инициализирует новый "чистый" экземпляр класса A и печатает словарь до и после добавления.
Ошибка (если вы еще не разобрались):
>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}
Во второй инициализации класса A словари не пустые, а начинаются с содержимого последней инициализации и т. Д. Я ожидал, что они начнут "заново".
Что решает эту «ошибку», так это добавление:
self.dict1 = {}
В конструкторе __init__
класса A. Однако это заставило меня задуматься:
- Что означает инициализация "dict1 = {}" в точке объявления dict1 (первая строка в классе A)? Это бессмысленно?
- Какой механизм создания экземпляров вызывает копирование ссылки из последней инициализации?
- Если я добавлю «self.dict1 = {}» в конструктор (или любой другой элемент данных), как это не повлияет на член словаря ранее инициализированных экземпляров?
РЕДАКТИРОВАТЬ: Следуя ответам, я теперь понимаю, что, объявив элемент данных и не ссылаясь на него в __init__
или где-либо еще как self.dict1, я практически определяю то, что в C ++ / Java называется статическим элементом данных , Называя его self.dict1, я делаю его привязанным к экземпляру.