Python - что является лучшим способом вызова метода суперкласса? - PullRequest
17 голосов
/ 29 ноября 2010

Все время я использовал:

SuperClass.__init__(self, *args, **kwargs)

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

Однако другие коды, с которыми я сталкивался, используют

super(MyClass, self).__init__(*args, **kwargs)

вместо.

Это может стать неоднозначным, если используется в:

class MyClass(SuperClass1, SuperClass2):
    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs) #which SuperClass is being used?

Я хотел бы знать, почему эта форма призвания получила широкое распространение? Есть ли какое-либо преимущество?

Ответы [ 3 ]

21 голосов
/ 29 ноября 2010

Причина, по которой super предпочтительнее для современных ( новый стиль ) классов, заключается в том, что он допускает кооперативное множественное наследование.Вот пример.

>>> class Foo(object):
...     def display(self):
...         print "In Foo"
... 
>>> class Foo2(Foo):
...     def display(self):
...         print "In Foo2"
...         super(Foo2, self).display()
...         print "Back in Foo2"
... 
>>> class Bar(Foo):
...     def display(self):
...         print "In Bar"
...         super(Bar, self).display()
...         print "Back in Bar"
... 
>>> class FooBar(Foo2, Bar):
...     pass
... 
>>> FooBar().display()
In Foo2
In Bar
In Foo
Back in Bar
Back in Foo2
>>> class BarFoo(Bar, Foo2):
...     pass
... 
>>> BarFoo().display()
In Bar
In Foo2
In Foo
Back in Foo2
Back in Bar

Обратите внимание, что я ничего не сделал для изменения метода display в суперклассах, но я получил другие методы display для подклассов, изменив порядок, в котором я расположил суперклассы.BarFoo и FooBar имеют разные методы.Это связано с тем, что они имеют различные Приказы разрешения методов

>>> BarFoo.__mro__
(<class '__main__.BarFoo'>, <class '__main__.Bar'>, <class '__main__.Foo2'>, <class '__main__.Foo'>, <type 'object'>)
>>> FooBar.__mro__
(<class '__main__.FooBar'>, <class '__main__.Foo2'>, <class '__main__.Bar'>, <class '__main__.Foo'>, <type 'object'>)

Это означает, что super разрешает разные классы для каждого подкласса, в который он вызывается. Это позволяет каждому переопределяющему методуизменить небольшую часть того, что происходит, и при этом позволить любому другому суперклассу вносить свой вклад в вызов метода, если они желают хорошо играть.

6 голосов
/ 29 ноября 2010

Для новых классов стилей, которые наследуются от object, используется super.

Атрибут __mro__ (порядок разрешения метода) типа отображает поиск разрешения методапорядок, используемый super.

>>> class X(object):
    pass

>>> class Y(object):
    pass

>>> class Z(X, Y):
    pass

>>> Z.__mro__
(<class '__main__.Z'>, <class '__main__.X'>, <class '__main__.Y'>, <type 'object'>)

Это определяет порядок для Z. Поскольку это Z(X, Y), X является первым в иерархии.Если бы Z(Y, X), Y предшествовало бы X.

Для классов старого стиля используется SuperClass.__init__(self, *args, **kwargs).

ОБНОВЛЕНИЕ:

ДляВаш вопрос относительно того, какой SuperClass используется.

>>> class First(object):
    pass

>>> class Second(object):
    def __init__(self, *args, **kwargs):
        print 'Second __init__ called'

>>> class MInherit(First, Second):
    def __init__(self):
        super(MInherit, self).__init__()

>>> i = MInherit()
Second __init__ called

Сначала First будет проверен на наличие __init__, так как First стоит первым в MRO.Так как в этом случае «First» не имеет __init__, поэтому вызывается Second.Если бы было __init__ в First, только это было бы названо.

3 голосов
/ 29 ноября 2010

В дополнение к уже опубликованным хорошим ответам, вот некоторая дополнительная информация:

  • Классы старого стиля (те, которые не являются производными от объекта) имеют метод в глубинупорядок разрешения.Классы старого стиля вызывают свои суперклассы так, как вы привыкли.

  • Классы нового стиля (те, которые являются производными от объекта) имеют более сложный порядок разрешения методов.На высшем уровне это сродни ширине, но сложнее.Смотрите это страница для превосходного объяснения.Использование «super ()» позволяет новым классам стилей следовать этому порядку разрешения метода.

  • Если вы используете классы нового стиля, вы все равно можете использовать старый стиль вызова суперклассови ваш код все еще будет работать.Различия становятся очевидными только для более сложных моделей множественного наследования.

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