I'm reading the source code implemting the paxos algorithm with Python 2.7. In the code, there are lots of methods which call the methods of superclass that there exactly isn't this method in the superclass and the names of these two methods are always the same. Is this a special feature for Python? eg. super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger) the superclass of SimpleSynchronizationStrategyMixin is object not containing the method "set_messenger". exactly the name of method, which this line of code belongs to, is also "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)
The code you posted seems strange indeed, and using this class on its own would indeed fail. For example, using the following minimal example:
class SimpleSynchronizationStrategyMixin(object):
def set_messenger(self, messenger):
super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger)
print('test')
test = SimpleSynchronizationStrategyMixin()
test.set_messenger(None)
would give an error, as you would have expected:
AttributeError: 'super' object has no attribute 'set_messenger'
However, the name of the class reveals the answer: it is a "mixin" class, a class that is intended to be mixed in with another class. So the class only adds certain functionality, and may make assumptions about methods being present in the super object (which is not object
in the case of the final object).
To demonstrate this, let's extend the above example with the following code:
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()
Here, the set_messenger
method is defined in SomeOtherClass
. The Demo
class then uses the SomeOtherClass
with the mixin to create the final object. When demo()
is called, it prints:
setting the messenger to 'some messenger'.
test
Note that the order of the super classes is important. If you would write class Demo(SomeOtherClass, SimpleSynchronizationStrategyMixin)
then the line "test" would not be printed.
For your specific paxos example, see server.py
, which contains:
class ReplicatedValue(DedicatedMasterStrategyMixin, ExponentialBackoffResolutionStrategyMixin, SimpleSynchronizationStrategyMixin, BaseReplicatedValue):
"""
Mixes the dedicated master, resolution, and synchronization strategies into the base class
""
Here you can see that a number of mixin classes are "added" to BaseReplicatedValue
to create ReplicatedValue
.
Note that super()
does not always return the "parent" object. If the method DedicatedMasterStrategyMixin.propose_update(self, ...)
calls super(DedicatedMasterStrategyMixin, self).propose_update(...)
, it finds the next propose_update()
method according to the Method Resolution Order (MRO). Simply said, it looks in all base classes from left to right, and returns the first method found. In this way, each method can call super()
without knowing which class is the "parent", so that still all necessary methods can be chained. The following example code demonstrates this:
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'>]
"""