问题描述
我想在类的所有混合中调用相同的方法。 这是两个变体:
class MixinA(object):
def get_id(self):
return "A"
class MixinB(object):
def get_id(self):
return "B"
class Base(object):
def get_id(self):
for base_class in inspect.getmro(self.__class__):
return ",".join(base_class.get_id())
class Instance(MixinA, MixinB, Base):
pass
class MyTestCase(unittest.TestCase):
def test_multiple_mixin_methods(self):
"""
Sadly, we cannot call all mixin methods.
:return:
"""
ids = set(Instance().get_id())
print(ids)
assert ids == {"A", "B"}
可悲的是,这失败了。 我只得到“ A”。 我想要一个包含“ A”和“ B”的列表,顺序无所谓。
我在这里做错什么了吗?
非常感谢
1楼
您需要调用super。 super调用MRO中的下一个方法,因此您将调用A =>B。您不需要Base类。
class MixinA(object):
def get_id(self):
return "A", super(MixinA, self).get_id()
class MixinB(object):
def get_id(self):
return "B"
class Instance(MixinA, MixinB):
pass
首先, Instance().get_id()
将调用A.get_id()
然后对super的调用将调用MRO中的下一个方法B
更新资料
class MixinA(object):
def get_id(self):
return "A"
class MixinB(object):
def get_id(self):
return "B"
class Base(object):
def get_id(self):
return set([base_class.get_id(self) for base_class in inspect.getmro(self.__class__)[2:-1]])
class Instance(Base, MixinA, MixinB):
pass
不像之前的mixins独立。 在此示例中,您需要在MRO中首先使用基类
2楼
该代码段通过了您的测试,但它很脆,恕我直言,肯定有设计气味。
此外,它还要求Base
首先出现在mro中(但这通常是使用基类和mixins时想要的):
class MixinA(object):
def get_id(self):
return "A"
class MixinB(object):
def get_id(self):
return "B"
class Base(object):
def get_id(self):
ids = set()
mro = self.__class__.__mro__
start = mro.index(Base) + 1
for cls in mro__[start:-1]:
get_id = getattr(cls, "get_id", None)
if get_id:
id = cls.get_id(self)
ids.add(id)
return ids
class Instance(Base, MixinA, MixinB):
pass
您也可以通过super
调用来使其工作(很好,有点...),但它也不是很漂亮,并且当您添加第三个mixin时(在Instance
库中测试带有和不MixinC
的代码段,情况就变得很难看)我的意思是):
def get_super_id(id, cls, obj):
try:
supid = super(cls, obj).get_id()
return id, supid
except AttributeError:
return id
class MixinA(object):
def get_id(self):
return get_super_id("A", MixinA, self)
class MixinB(object):
def get_id(self):
return get_super_id("B", MixinB, self)
class MixinC(object):
def get_id(self):
return get_super_id("C", MixinC, self)
class Base(object):
pass
class Instance(Base, MixinA, MixinB, MixinC):
pass
实际上,我最不喜欢整个想法的事情是get_id
返回一个值或一个集合。
这以不可预测的方式破坏了期望。