Я только что недавно столкнулся с ошибкой в Python. Это был один из тех глупых ошибок новичка, но он заставил меня задуматься о механизмах Python (я долго программист на С++, новый для 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 = {}" в конструкторе (или любом другом элементе данных), как это не повлияет на член словаря ранее инициализированных экземпляров?
EDIT: после ответов я теперь понимаю, что, объявив член данных, а не ссылаясь на него в __init__
или где-то еще как self.dict1, я практически определяю, что вызвано в С++/Java статическим элементом данных, Вызывая его self.dict1, я делаю его "связанным с экземпляром".