Наследование и переопределение __init__ в python - PullRequest
115 голосов
/ 16 апреля 2009

Я читал 'Dive Into Python', и в главе о классах он приводит такой пример:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

Затем автор говорит, что если вы хотите переопределить метод __init__, вы должны явно вызвать родительский элемент __init__ с правильными параметрами.

  1. Что, если у этого FileInfo класса было более одного класса предков?
    • Должен ли я явно вызывать все методы __init__ классов-предков?
  2. Кроме того, я должен сделать это с любым другим методом, который я хочу переопределить?

Ответы [ 5 ]

143 голосов
/ 16 апреля 2009

Книга немного устарела в отношении вызова подкласса-суперкласса. Это также немного устарело относительно встроенных классов подкласса.

В наши дни это выглядит так.

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super( FileInfo, self ).__init__()
        self["name"] = filename

Обратите внимание на следующее.

  1. Мы можем напрямую создавать подклассы встроенных классов, таких как dict, list, tuple и т. Д.

  2. Функция super обрабатывает отслеживание суперклассов этого класса и соответственно вызывает в них функции.

16 голосов
/ 15 июня 2012

В каждом классе, от которого вам нужно наследовать, вы можете запустить цикл каждого класса, который требует init'd при инициации дочернего класса ... пример, который можно скопировать, может быть лучше понят ...

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name
14 голосов
/ 16 апреля 2009

На самом деле нет для вызова __init__ методов базового класса (классов), но вы обычно хотите сделать это, потому что базовые классы будут делать некоторые важные инициализации, необходимые для работы остальных методов классов.

Для других методов это зависит от ваших намерений. Если вы просто хотите что-то добавить к поведению базовых классов, вам нужно вызвать метод базовых классов дополнительно к вашему собственному коду. Если вы хотите кардинально изменить поведение, вы можете не вызывать метод базового класса и реализовывать все функциональные возможности непосредственно в производном классе.

4 голосов
/ 16 апреля 2009

Если класс FileInfo имеет более одного класса-предка, вам определенно следует вызвать все их функции __init __ (). Вы также должны сделать то же самое для функции __del __ (), которая является деструктором.

2 голосов
/ 16 апреля 2009

Да, вы должны позвонить __init__ для каждого родительского класса. То же самое касается функций, если вы переопределяете функцию, которая существует у обоих родителей.

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