Наследование атрибутов в python с использованием __init__
Я человек Java, который только начал изучать Python. Возьмите этот пример:
class Person():
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Teenager(Person):
def __init__(self, name, phone, website):
self.name=name
self.phone=phone
self.website=website
Я уверен, что есть много избыточного кода (я знаю на Java, есть много избыточности для бит кода выше).
Какие части являются избыточными, по отношению к которым атрибуты уже унаследованы от родительского класса?
Ответы
Ответ 1
При написании функции __init__
для класса в python вы всегда должны вызывать функцию __init__
своего суперкласса. Мы можем использовать это для передачи соответствующих атрибутов непосредственно в суперкласс, поэтому ваш код будет выглядеть так:
class Person(object):
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Teenager(Person):
def __init__(self, name, phone, website):
Person.__init__(self, name, phone)
self.website=website
Как указывали другие, вы можете заменить строку
Person.__init__(self, name, phone)
с
super(Teenager, self).__init__(name, phone)
и код будет делать то же самое. Это связано с тем, что в python instance.method(args)
просто сокращается Class.method(instance, args)
. Если вы хотите использовать super
, вам нужно убедиться, что вы указываете object
в качестве базового класса для Person
, как это было в моем коде.
документация python содержит дополнительную информацию о том, как использовать ключевое слово super
. Важным в этом случае является то, что он говорит python искать метод __init__
в суперклассе self
, который не является Teenager
Ответ 2
Чуть более чистый способ мне нравится:
class Teenager(Person):
def __init__(self, *args, **kwargs):
self.website=kwargs.pop('website')
super(Teenager, self).__init__(*args, **kwargs)
В этом случае это не имеет большого значения, но когда у вас есть __init__
с множеством аргументов, это облегчает жизнь.
Ответ 3
Атрибуты в Python не наследуются, когда они определены в конструкторе, а конструктор родительского класса не вызывается, если вы не выполните все его вручную:
class Person():
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Teenager(Person):
def_init_(self, name, phone, website):
Person.__init__(self, name, phone) # Call parent class constructor.
self.website=website
Подробнее об этом здесь: http://docs.python.org/tutorial/classes.html#inheritance
Ответ 4
__init__
, в отличие от конструктора java, автоматически не вызывается для каждого класса в иерархии наследования - вам нужно сделать это самостоятельно.
Кроме того, все ваши иерархии объектов должны внедряться в object
(за исключением особых случаев).
Ваш код должен читать:
class Person(object):
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Teenager(Person):
def_init_(self, name, phone, website):
super(Teenager, self).__init__(name, phone)
self.website=website
super
создает делегат для своего второго аргумента (self
), который вызывает следующую функцию в списке функций для вызова каждого имени ( "порядок разрешения метода" ). Это не совсем то же самое, что вызывать метод суперкласса, как это происходит в Java.
Вы также можете написать super(type(self), self).__init__(name, phone)
, но если вы наследуете дальше от этого класса, type(self)
может быть не Teenager
, и вы можете иметь бесконечную рекурсию. Это одно практическое следствие того, что вы работаете с объектом делегата с разницей MRO, а не напрямую вызываете конструктор суперкласса.