Когда я создаю экземпляр подкласса python, он перезаписывает атрибут базового класса
Код выглядит так:
class A(object): x = 0 y = 0 z = [] def __init__(self): super(A, self).__init__() if not self.y: self.y = self.x if not self.z: self.z.append(self.x) class B(A): x = 1 class C(A): x = 2 print C().y, C().z print B().y, B().z
Выход
2 [2] 1 [2]
Почему z
перезаписывается, но не y
? Это потому, что это не неизменный тип? Я посмотрел документацию на python и не нашел объяснений.
- Почему я должен использовать классы в python?
- что делает несколько __init__ в одном классе?
- Как получить доступ к переменной, инициализированной в родительском классе, с помощью объекта Child?
- вложенные классы в Python
- какая разница между dir (self) и self .__ dict__
Да, это потому, что он неизменен, а другой нет. Вернее, это то, что вы мутируете одно, а не другое. (Важно то, что объект «изменен», имеет значение, действительно ли вы его мутируете.) Это также потому, что вы используете переменные класса вместо переменных экземпляра (см. Этот вопрос ).
В определении класса вы создаете три переменные класса, разделяемые между всеми экземплярами класса. После создания экземпляра вашего класса, если вы делаете self.x
в этом экземпляре, он не найдет x
в качестве атрибута экземпляра, но будет искать его в классе. Точно так же self.z
будет искать класс и найти тот, что есть на классе. Обратите внимание, что поскольку вы сделали z
переменной класса, существует только один список, который будет использоваться для всех экземпляров класса (включая все экземпляры всех подклассов, если они не переопределяют z
).
Когда вы делаете self.y = self.x
, вы создаете новый атрибут, атрибут экземпляра , только для экземпляра.
Однако, когда вы делаете self.z.append(...)
, вы не создаете новую переменную экземпляра. Скорее, self.z
просматривает список, хранящийся в классе, а затем append
мутации, которые перечислены. Нет «переписывания». Существует только один список, и когда вы добавляете приложение, вы меняете его содержимое. ( if not self.z
только один элемент, потому что у вас есть, if not self.z
, поэтому после добавления одного из них это неверно, а последующие вызовы не добавляют ничего больше.)
Результатом является то, что чтение значения атрибута не совпадает с назначением ему. Когда вы читаете значение self.x
, вы можете получить значение, которое хранится в классе и разделяемое между всеми экземплярами. Однако, если вы присваиваете значение self.x
, вы всегда назначаете атрибут экземпляра; если уже есть атрибут класса с тем же именем, ваш атрибут экземпляра скроет это.
Проблема в том, что x
и y
неизменяемы, а z
изменчиво, и вы мутируете его.
self.z.append()
не заменяет z
, он просто добавляет элемент в z
.
После запуска C()
в print C().y, C().z
(который создает два разных объекта C
) self.z
больше не оценивает False
потому что он больше не пуст.
Если вы измените две линии print
, вы увидите, что
1 [1] 2 [1]
Когда Python оценивает тело class A
он создает экземпляр одного объекта list
и назначает его z
. Так как подклассы не переопределяют его, и поскольку объекты list
хранятся по ссылке в Python, все три класса имеют один и тот же список z
, поэтому первая, которую вы создаете, получает, чтобы заполнить z
а затем остальные просто получают все, что было там поставлено. Хотя вы изменили содержимое списка, вы не изменили, к какому списку z
относится.
Это не влияет на y
потому что вы назначаете целое число непосредственно во внутренний словарь объекта, заменяя предыдущее значение.
Чтобы исправить это, создайте свой массив внутри конструктора, присвоив:
class A(object): x = 0 y = 0 z = None def __init__(self): super(A, self).__init__() if not self.y: self.y = self.x if not self.z: # create a new list z = [self.x] class B(A): x = 1 class C(A): x = 2 print C().y, C().z print B().y, B().z
- Внутренняя работа scipy.integrate.ode
- Как использовать multiprocessing.Pool правильно с PySide для создания неблокирующего графического интерфейса
- python: закрытие и классы
- Как использовать классы, полученные из класса списка Python
- ООП – организация больших классов
- Как получить доступ к классу класса суперкласса?
- python самостоятельно
- Наследование класса Python: вызов функции производного класса
- Как подойти к реализации «Class Card» в соответствии с требованиями учебника Python
- Каков наиболее эффективный способ возврата нескольких значений из метода класса в Python?
- Классовые аргументы класса в Python 3