Ответ 1
Использование super()
, __init__()
и множественное наследование немного сложнее.
В обычном потоке вещей каждый метод вызывает super()
, а классы, которые наследуют только от object
, выполняют небольшую дополнительную работу, чтобы убедиться, что метод действительно существует: он будет выглядеть примерно так:
>>> class Foo(object):
... def frob(self, arg):
... print "Foo.frob"
... if hasattr(super(Foo, self), 'frob'):
... super(Foo, self).frob(arg)
...
>>> class Bar(object):
... def frob(self, arg):
... print "Bar.frob"
... if hasattr(super(Bar, self), 'frob'):
... super(Bar, self).frob(arg)
...
>>> class Baz(Foo, Bar):
... def frob(self, arg):
... print "Baz.frob"
... super(Baz, self).frob(arg)
...
>>> b = Baz()
>>> b.frob(1)
Baz.frob
Foo.frob
Bar.frob
>>>
Но когда вы пытаетесь сделать что-то подобное по методу, который на самом деле имеет object
, все становится немного рискованным; object.__init__
не принимает аргументов, поэтому о единственном безопасном способе использовать это вызов super().__init__()
без аргументов, так как этот вызов может обрабатываться object.__init__
. Но тогда это может не обрабатываться object.__init__
, а вместо этого обрабатываться классом в другом месте в графе наследования. Таким образом, любой класс, который определяет __init__
в иерархии класса множественного наследства, должен быть готов к вызову без аргументов.
Один из способов борьбы с этим - никогда не использовать аргументы в __init__()
. Выполняйте минимальную инициализацию и полагайтесь на настройку свойств или используя другие средства для настройки нового объекта перед использованием. Это довольно неприятно, однако.
Другой способ - использовать только аргументы ключевого слова, что-то вроде def __init__(self, **keywords):
и всегда удалять аргументы, относящиеся к данному конструктору. Это стратегия на основе надежда, вы надеетесь, что все ключевые слова будут потребляться до того, как управление достигнет уровня object.__init__
.
Третий способ - определить суперкласс для всех многонаследованных баз, который сам определяет __init__
каким-то полезным способом и не вызывает super().__init__
(object.__init__
- это no-op). Это означает, что вы можете быть уверены, что этот метод всегда называется последним, и вы можете делать то, что вам нравится, с вашими аргументами.