#python #class #python-3.x #inheritance #attributes
#python #класс #python-3.x #наследование #атрибуты
Вопрос:
Рассмотрим следующий пример. У Parent
класса есть атрибут, который называется attr
. Оба Child1
и Child2
имеют атрибут с одинаковым именем. Единственное различие между Child1
и Child2
заключается в том, что Child1
вызовы super()
выполняются перед переопределением attr
атрибута родителя. Child2
вместо этого, похоже, не переопределяет родительский, attr
потому что атрибут определен перед super()
вызовом. Есть ли способ Child2
переопределить атрибут родительского класса attr
при определении его перед super()
вызовом?
class Parent():
def __init__(self):
self.attr = "parent"
class Child1(Parent):
def __init__(self):
super().__init__()
self.attr = "child1"
class Child2(Parent):
def __init__(self):
self.attr = "child2"
super().__init__()
if __name__ == '__main__':
child1 = Child1()
print(child1.attr) # "child1"
child2 = Child2()
print(child2.attr) # "parent"
Ответ №1:
Не существует таких понятий, как «родительский attr
« и «дочерний attr
«. В этом экземпляре есть только один attr
, независимо от того, был ли он установлен из кода в родительском классе, или из кода в дочернем классе, или из кода без класса.
Другими словами, эти примеры дают одинаковые результаты:
Пример 1
class A:
def __init__(self):
self.attr = 1
class B(A):
pass
b = B()
Пример 2
class A:
pass
class B(A):
def __init__(self):
self.attr = 1
b = B()
Пример 3
class A:
pass
class B(A):
pass
b = B()
b.attr = 1
Фактический ответ 😉
Итак, разница между Child1
и Child2
заключается в том, что Child1
‘s __init__
выполняет это:
self.attr = "parent"
self.attr = "child1"
И Child2
‘s __init__
эффективно делает это:
self.attr = "child2"
self.attr = "parent"
Ответ №2:
Нет. super().__init__()
это сокращение для вызова суперкласса __init__
, передавая ему текущий экземпляр как self
.
Рассмотрим, что происходит при создании экземпляра Child2
. Сначала создается «голый» экземпляр класса. Этот экземпляр должен быть инициализирован. Для этого Python передает этот экземпляр в Child2.__init__
as self
. Теперь Child2.__init__
сначала добавляется attr
атрибут к этому экземпляру. Но затем он вызывает, super().__init__()
который, в данном случае, является сокращением для Parent.__init__(self)
. Важно, self
является ли экземпляр Child2
экземпляром, который мы инициализируем. Таким образом, Parent.__init__
затем перезаписывается attr
атрибут этого экземпляра.
В общем, вероятно, лучше всего сначала поместить super().__init__()
вызов в ваш подкласс __init__
. На самом деле это не ограничение, и большинство людей ожидают, что оно будет первым.
Пример, демонстрирующий работу программы:
class Parent(object):
def __init__(self):
print('Here I am, in the parent! My ID is: ' str(id(self)))
class Child(Parent):
def __init__(self):
print('Initializing new Child instance with ID: ' str(id(self)))
super().__init__()
Таким образом, что при создании экземпляра Child
выводится:
Initializing new Child instance with ID: 4372063120
Here I am, in the parent! My ID is: 4372063120