2016-07-19 12 views
2
class Base(object): 
    def m(self): 
     print 'base' 


class MixinA(Base): 
    def m(self): 
     super(MixinA, self).m() 
     print 'mixin a' 


class MixinB(Base): 
    def m(self): 
     super(MixinB, self).m() 
     print 'mixin b' 


class Top(MixinB, MixinA, Base): 
    def m(self): 
     super(Top, self).m() 
     print 'top' 


t = Top() 
t.m() 

Печатается:ли супер попробовать каждый класс в MRO

base 
mixin a 
mixin b 
top 

Я удивлен несколько вещей. Во-первых MRO из Top является (<class 'Top'>, <class 'MixinB'>, <class 'MixinA'>, <class 'Base'>, <type 'object'>)

  1. Почему mixin a предшествует mixin b?
  2. Does super попробовать каждый класс в MRO (в отличие от поиска атрибута при возврате первого атрибута)?

ответ

6

Нет, super() не «пробует» каждый класс в MRO. Ваш код цепи вызовы, потому что каждый вызванный метод имеет другойsuper() звонок в нем. Top.m() звонки super().m(), который разрешается до MixinB.m(); который, в свою очередь, использует super() снова и т.д.

mixin a выводится перед mixin b, потому что вы печатаете после на super() вызов, поэтому последний элемент в МРО выполняется первым. Вызов super() равен только другим способом:, поэтому оператор print после такого вызова не будет выполнен до завершения вызова super().m().

Ваш MRO выглядит следующим образом:

>>> type(t).__mro__ 
(<class '__main__.Top'>, <class '__main__.MixinB'>, <class '__main__.MixinA'>, <class '__main__.Base'>, <type 'object'>) 

так естественно Base.m() называется последним и получает печать первый, а затем MixinA, затем MixinB и Top быть последним для печати.

Обратите внимание, что используется MRO self, а не класс, который вы передаете в super() в качестве первого аргумента; MRO, таким образом, стабилен во всех вызовах вашей иерархии для любого данного экземпляра.

Если вы ожидали, что операторы печати, которые будут выполнены в том порядке, MRO вызовы прикован, вы должны поставить printЗАЯВЛЕНИЯ до того вызова следующего m() метода в MRO.

3

Там нет пытается участие, здесь: Ваш заказ вызов

  • Top.m() вызова super(Top, self).m(), который MixinB.m().

  • MixinB.m() немедленно вызывает super(MixinB, self).m() который MixinA.m() при вызове с type(self) == Top. super() использует MRO объекта self, поэтому нам нужно посмотреть Top, а не на автономный MixinB.

  • MixinA.m() звонки super(MixinA, self).m() который Base.m().

Есть не более супер звонки в этой точке, так

  • Base делает то print 'base' и возвращается (в MixinA.m())
  • MixinA.m() печатает 'mixin a' и возвращает (в MixinB.m())
  • MixinB.m() печатает 'mixin b' и возвращает (до Top.m()).
  • Top.m() отпечатки 'top' и возвращается вызывающему.

Отпечатки в порядке обратного вызова, потому что вы выполняете их после супервызов.

+0

'super (MixinB) .m()' не вызывает 'MixinA.m()' – Marii

+0

@Marii: да, это так. 'MixinA' - следующий класс в MRO' type (self) '. –

+0

@Marii: Не путайте. Мы используем MRO 'Top', а не' MixinB' как отдельный класс. При смешивании в 'Top', как показано,' super (MixinB, self) '(с' type (self) == Top') на самом деле 'MixinA'. – dhke