#python
Вопрос:
Я распознаю странное поведение в своем коде. Я извлекаю некоторый тестовый код, чтобы продемонстрировать:
class A: def __init__(self): super().__init__() self.mystr = 'A' self.mydict['key'] = 'value' class B(A): mystr = 'B' mydict = {} def __init__(self, name): print(name, 'mystr (before)', self.mystr) print(name, 'mydict (before)', self.mydict) super().__init__() print(name, 'mystr (after)', self.mystr) print(name, 'mydict (after)', self.mydict) if __name__ == '__main__': b1 = B('b1') b2 = B('b2')
На выходе получается:
b1 mystr (before) B b1 mydict (before) {} b1 mystr (after) A b1 mydict (after) {'key': 'value'} b2 mystr (before) B b2 mydict (before) {'key': 'value'} // lt;- I expect this to be {} b2 mystr (after) A b2 mydict (after) {'key': 'value'}
Отель mystr
работает так, как я и ожидал. Во втором случае b2
это «B», как оно было инициализировано. Но свойство mydict
инициализировано неправильно для второго экземпляра и содержит пару ключ/значение:
b2 mydict (до) {‘ключ’: ‘значение’}
Я знаю, что в Python есть изменяемые и неизменяемые переменные и что первые из них хранятся по ссылке. Но я могу объяснить, почему мой код работает не так, как ожидалось.
Может кто-нибудь дать мне подсказку?
Ответ №1:
Да, у вас есть один диктант, общий для всех экземпляров класса. Ключ в том, что
self.mydict['key'] = 'value'
не является назначением атрибута mydict
, поэтому он не создает новый атрибут экземпляра. Скорее, это вызов метода
self.mydict.__setitem__('key', 'value')
и поиск self.mydict
будет разрешен A.mydict
, так как нет именованного атрибута экземпляра mydict
.
С другой стороны,
self.mystr = 'A'
является присвоением атрибуту, поэтому он всегда создает новый атрибут экземпляра, если он еще не существует, вместо того, чтобы изменять значение существующего атрибута класса с тем же именем. Если вы хотите изменить значение атрибута класса с помощью экземпляра класса, вам сначала нужно получить ссылку на класс с помощью чего-то вроде
self.__class__.mystr = 'A' # Modifies A.mystr without creating self.mystr instead
Комментарии:
1. Я вижу, что я определяю атрибуты класса — я понимаю. И с собой.мистр = … Я создаю атрибут экземпляра, который затеняет атрибут класса, верно?
2. Правильный. Существует асимметрия между атрибутами класса и экземпляра. Доступ к атрибуту через экземпляр может вернуться к доступу к атрибуту класса, но назначение атрибута через экземпляр всегда создает атрибут экземпляра, если он не существует.