Наследование и переопределение __init__ в python

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

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

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

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

Ответ 1

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

Теперь это выглядит так.

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

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

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

  • Функция super обрабатывает отслеживание суперклассов класса и вызывающих функций в них соответствующим образом.

Ответ 2

В каждом классе, который вам нужно унаследовать, вы можете запустить цикл каждого класса, который требует 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

Ответ 3

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

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

Ответ 4

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

Ответ 5

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