我想在我班级的所有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):
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',顺序并不重要。
我在这里做错了什么?
非常感谢
答案 0 :(得分:1)
你需要的是打电话给超级。 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
不像mixin独立之前那样。在此示例中,您需要Base类在MRO中的第一个
答案 1 :(得分:1)
这个片段通过了你的测试,但它很脆弱,恕我直言,这是一个确定的设计气味。此外,它要求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时,事情开始变得难看(测试在MixinC
基础中使用和不使用Instance
的代码段来查看我的意思):
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
返回单个值或集合。这以不可预测的方式打破了期望。