Наследование атрибутов с использованием __init__ - PullRequest
39 голосов
/ 13 января 2012

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

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

Ответы [ 5 ]

44 голосов
/ 13 января 2012

При написании функции __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

15 голосов
/ 13 января 2012

Чуть чище, мне нравится это делать:

class Teenager(Person):
        def __init__(self, *args, **kwargs):
           self.website=kwargs.pop('website')
           super(Teenager, self).__init__(*args, **kwargs)

Это не имеет большого значения в этом случае, но когда у вас есть __init__ с кучей аргументов, это облегчает жизнь.

6 голосов
/ 13 января 2012

Атрибуты в 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

5 голосов
/ 27 марта 2018

Все примеры до сих пор были для Python 2.x, но вот решение для Python 3.x, которое использует более короткую версию super () и не наследуется от объекта.

class Person:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        super().__init__(name, phone)
        self.website = website
1 голос
/ 13 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...