Кажется, нет хорошей онлайн-документации по этому вопросу: Если я создаю производный класс, автоматически ли он будет иметь все атрибуты базового класса? Но для чего нужен BaseClass.__init()
, вам также нужно сделать это для других методов базового класса? Нужно ли аргументы BaseClass.__init__()
? Если у вас есть аргументы для вашего базового класса __init__()
, они также используются производным классом, вам нужно явно указать аргументы на производный код classe __init__()
или вместо них вместо BaseClass.__init__()
?Атрибуты класса и базового класса на основе Python?
ответ
If I make a derived class, will it automatically have all the attributes of the base class?
Атрибуты класса, да. Атрибуты экземпляра нет (просто потому, что они не существуют при создании класса), если в производном классе нет __init__
, и в этом случае вместо него будет вызываться базовый, и будут установлены атрибуты экземпляра.
Does BaseClass.init() need arguments?
В зависимости от класса и его знака __init__
. Если вы явно вызываете Base.__init__
в производном классе, вам, по крайней мере, нужно будет передать self
в качестве первого аргумента. Если у вас есть
class Base(object):
def __init__(self):
# something
, то это довольно очевидно, что никакие другие аргументы не принимаются __init__
. Если бы
class Base(object):
def __init__(self, argument):
# something
, то вы должны пройти argument
при вызове базы __init__
. Здесь нет ракеты.
If you have arguments for your base class init(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe's init(), or set them to BaseClass.init() instead?
Опять же, если производный класс не имеет __init__
, база одна будет использоваться вместо этого.
class Base(object):
def __init__(self, foo):
print 'Base'
class Derived(Base):
pass
Derived() # TypeError
Derived(42) # prints Base
В другом случае вам необходимо как-то позаботиться об этом. Используете ли вы *args, **kwargs
и просто передаете аргументы без изменений в базовый класс или копируете подпись базового класса или поставляете аргументы из других источников, зависит от того, что вы пытаетесь выполнить.
Если вы реализуете __init__
в классе, производном от BaseClass, то он перезапишет унаследованный метод __init__
, и поэтому BaseClass.__init__
никогда не будет вызван. Если вам нужно вызвать метод __init__
для BaseClass (как это обычно бывает), то вам нужно сделать это, и его сделать явно, вызвав BaseClass.__init__
, как правило, из недавно реализованного метода __init__
.
class Foo(object):
def __init__(self):
self.a = 10
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
self.b = 20
bar = Bar()
bar.do_something()
Это вызовет следующую ошибку:
AttributeError: 'Bar' object has no attribute 'a'
Таким образом, метод do_something
был унаследован, как и ожидалось, но этот метод требует атрибут a
, был установлен, что он никогда не потому, что __init__
также была перезаписана. Мы оборачиваем это, явно называя Foo.__init__
с Bar.__init__
.
class Foo(object):
def __init__(self):
self.a = 10
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
Foo.__init__(self)
self.b = 20
bar = Bar()
bar.do_something()
который печатает 10
как и ожидалось.Foo.__init__
в этом случае ожидает единственный аргумент, который является экземпляром Foo
(который по соглашению называется self
).
Обычно, когда вы вызываете метод в экземпляре класса, экземпляр класса автоматически передается в качестве первого аргумента. Методы для экземпляра класса называются связанными методами. bar.do_something
- пример связанного метода (и вы заметите, что он вызывается без каких-либо аргументов). Foo.__init__
- это несвязанный метод, поскольку он не привязан к конкретному экземпляру Foo
, поэтому первый аргумент, экземпляр Foo
, должен быть явно передан.
В нашем случае, мы переходим к self
Foo.__init__
, который является экземпляром Bar
, который был передан методу __init__
в Bar
. Так как Bar
наследует от Foo
, экземпляры Bar
также являются экземплярами Foo
, поэтому разрешается прохождение self
до Foo.__init__
.
Возможно, что класс, который вы наследуете, требует или принимает больше аргументов, чем просто экземпляр класса. Они рассматриваются как вы бы с любым способом вы звоните внутри __init__
:
class Foo(object):
def __init__(self, a=10):
self.a = a
def do_something(self):
print self.a
class Bar(Foo):
def __init__(self):
Foo.__init__(self, 20)
bar = Bar()
bar.do_something()
, который будет печатать 20
.
Если вы пытаетесь реализовать интерфейс, который полностью раскрывает все аргументы инициализации базового класса через ваш класс наследования, вам нужно будет сделать это явно. Обычно это делается с аргументами * args и ** kwargs (имена по соглашению), которые являются заполнителями для всех остальных аргументов, которые явно не указаны. Следующий пример использует все, что я обсуждал:
class Foo(object):
def __init__(self, a, b=10):
self.num = a * b
def do_something(self):
print self.num
class Bar(Foo):
def __init__(self, c=20, *args, **kwargs):
Foo.__init__(self, *args, **kwargs)
self.c = c
def do_something(self):
Foo.do_something(self)
print self.c
bar = Bar(40, a=15)
bar.do_something()
В этом случае аргумент c
устанавливается равным 40, так как это первый аргумент Bar.__init__
. Второй аргумент затем включается в переменные args
и kwargs
(* и ** - это особый синтаксис, который говорит о расширении списка/кортежа или словаря в отдельные аргументы при передаче функции/методу) и передается по Foo.__init__
.
В этом примере также указывается, что любой перезаписанный метод должен быть вызван явно, если это то, что требуется (поскольку в этом случае do_something
).
В последнем случае вы часто увидите super(ChildClass, self).method()
(где ChildClass
- это произвольный дочерний класс), который используется вместо вызова метода BaseClass
явно. Обсуждение super
- это еще один вопрос, но достаточно сказать, что в этих случаях его обычно используют для выполнения именно того, что делается, вызывая BaseClass.method(self)
. Вкратце, super
делегирует вызов метода следующему классу в порядке разрешения метода - MRO (который в одиночном наследовании является родительским классом). См. documentation on super для получения дополнительной информации.
- 1. Кастинг на основе базового класса
- 2. Xml-сериализация Атрибуты базового класса
- 3. Понимание Python класса и базового класса
- 4. Как фильтровать коллекцию базового класса на основе поля производного класса?
- 5. Атрибуты атрибутов Python и класса
- 6. понимание базового класса Python
- 7. Атрибуты класса Python и модуля
- 8. Python Атрибуты класса и подклассов
- 9. Осмотреть атрибуты класса python
- 10. Атрибуты класса Python - сброс
- 11. Использование нескольких репозиториев на основе базового класса класса
- 12. Выбор аргументы шаблона базового класса на основе полученных аргументов класса
- 13. Свойства/атрибуты класса Python
- 14. Атрибуты методов/элементов виртуального базового класса в наследовании класса C#
- 15. Атрибуты класса в Python
- 16. Отражать атрибуты из производного класса с использованием базового класса
- 17. Атрибуты класса Python, не наследующие
- 18. CoreData: атрибуты базового класса не являются постоянными
- 19. Фильтровать атрибуты класса на основе типа
- 20. предупреждения Raising на основе класса атрибуты
- 21. подклассов класса Python наследовать атрибуты класса супер
- 22. Python: переменные базового класса печати
- 23. атрибуты класса python не установлены?
- 24. Python - Тестирование абстрактного базового класса
- 25. Инициализация класса Python - атрибуты памяти
- 26. Функция друга базового класса и производного класса
- 27. Понимание базового класса Java и производного класса
- 28. Получить атрибуты класса и экземпляра в Python
- 29. Python получить прямые атрибуты класса
- 30. Указатель базового класса извлечения