为什么可以调用超类没有的方法

Why can call a method that the superclass does not have

我正在阅读使用 Python 2.7 实现 paxos 算法的源代码。在代码中,有很多方法调用了超类的方法,而超类中并没有这个方法,而且这两个方法的名称总是相同的。这是 Python 的特殊功能吗? 例如。超级(SimpleSynchronizationStrategyMixin,自我)。set_messenger(信使) SimpleSynchronizationStrategyMixin 的超类是不包含方法 "set_messenger" 的对象。这行代码所属的方法名也是"set_messenger"

class SimpleSynchronizationStrategyMixin(object):

    sync_delay = 10.0

    def set_messenger(self, messenger):
        super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger)

        def sync():
            self.messenger.send_sync_request(random.choice(self.peers), self.instance_number)

        self.sync_task = task.LoopingCall(sync)
        self.sync_task.start(self.sync_delay)


    def receive_sync_request(self, from_uid, instance_number):
        if instance_number < self.instance_number:
            self.messenger.send_catchup(from_uid, self.instance_number, self.current_value)


    def receive_catchup(self, from_uid, instance_number, current_value):
        if instance_number > self.instance_number:
            print 'SYNCHRONIZED: ', instance_number, current_value
            self.advance_instance(instance_number, current_value, catchup=True)

您发布的代码确实看起来很奇怪,单独使用此 class 确实会失败。例如,使用以下最小示例:

class SimpleSynchronizationStrategyMixin(object):

    def set_messenger(self, messenger):
        super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger)
        print('test')


test = SimpleSynchronizationStrategyMixin()
test.set_messenger(None)

如您所料,会报错:

AttributeError: 'super' object has no attribute 'set_messenger'

然而,class的名字揭示了答案:它是一个"mixin"class,一个class本来就是与另一个 class 混在一起。因此 class 仅添加某些功能,并且可能对超级对象中存在的方法做出假设(在最终对象的情况下是 而不是 object ).

为了证明这一点,让我们用下面的代码扩展上面的例子:

class SomeOtherClass(object):

    def set_messenger(self, messenger):
        print('setting the messenger to %s.' % repr(messenger))


class Demo(SimpleSynchronizationStrategyMixin, SomeOtherClass):

    def demo(self):
        self.set_messenger('some messenger')


demo = Demo()
demo.demo()

这里,set_messenger方法定义在SomeOtherClass中。 Demo class 然后使用 SomeOtherClass 和 mixin 创建最终对象。当 demo() 被调用时,它打印:

setting the messenger to 'some messenger'.
test

请注意,超级 classes 的顺序很重要。如果你写 class Demo(SomeOtherClass, SimpleSynchronizationStrategyMixin) 那么行 "test" 就不会被打印出来。

有关您的特定 paxos 示例,请参阅 server.py,其中包含:

class ReplicatedValue(DedicatedMasterStrategyMixin, ExponentialBackoffResolutionStrategyMixin, SimpleSynchronizationStrategyMixin, BaseReplicatedValue):
    """
    Mixes the dedicated master, resolution, and synchronization strategies into the base class
    ""

在这里你可以看到一些mixin classes是"added"到BaseReplicatedValue来创建ReplicatedValue.

请注意 super() 并不总是 return "parent" 对象。如果方法DedicatedMasterStrategyMixin.propose_update(self, ...)调用了super(DedicatedMasterStrategyMixin, self).propose_update(...),则根据Method Resolution Order (MRO)找到下一个propose_update()方法。简单地说,它从左到右查找所有基 classes,returns 是找到的第一个方法。这样,每个方法都可以在不知道哪个 class 是 "parent" 的情况下调用 super(),因此仍然可以链接所有必要的方法。以下示例代码演示了这一点:

class Base(object):
    def test(self):
        # NB: No super() call in the base class!
        print('Test Base')
        print('')

class MixinX(object):
    def test(self):
        print('Test X')
        super(MixinX, self).test()

class MixinY(object):
    def test(self):
        print('Test Y')
        super(MixinY, self).test()

class MixinZ(object):
    def test(self):
        print('Test Z')
        super(MixinZ, self).test()

class Final(Base):
    pass

class FinalX(MixinX, Base):
    pass

class FinalXYZ(MixinX, MixinY, MixinZ, Base):
    pass

class FinalZYX(MixinZ, MixinY, MixinX, Base):
    pass

class WrongOrder(Base, MixinX, MixinY, MixinZ):
    pass

class MixinsOnly(MixinX, MixinY, MixinZ):
    pass


"""
>>> Final().test()
Test Base

>>> FinalX().test()
Test X
Test Base

>>> FinalXYZ().test()
Test X
Test Y
Test Z
Test Base

>>> FinalZYX.test()
Test Z
Test Y
Test X
Test Base

>>> WrongOrder().test()
Test Base

>>> MixinsOnly().test()
Test X
Test Y
Test Z
Traceback (most recent call last):
  File "superdemo.py", line 36, in <module>
    MixinsOnly().test()
  File "superdemo.py", line 9, in test
    super(MixinX, self).test()
  File "superdemo.py", line 14, in test
    super(MixinY, self).test()
  File "superdemo.py", line 19, in test
    super(MixinZ, self).test()
AttributeError: 'super' object has no attribute 'test'

>>> FinalXYZ.mro()
[<class '__main__.FinalXYZ'>, <class '__main__.MixinX'>, <class '__main__.MixinY'>, <class '__main__.MixinZ'>, <class '__main__.Base'>, <type 'object'>]
"""