Подтвердить что ты не робот

Наследование атрибутов в 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, есть много избыточности для бит кода выше).

Какие части являются избыточными, по отношению к которым атрибуты уже унаследованы от родительского класса?

4b9b3361

Ответ 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, а не напрямую вызываете конструктор суперкласса.