当前位置: 代码迷 >> python >> 无法在所有基类上调用相同的方法
  详细解决方案

无法在所有基类上调用相同的方法

热度:91   发布时间:2023-06-16 14:08:53.0

我想在类的所有混合中调用相同的方法。 这是两个变体:

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”的列表,顺序无所谓。

我在这里做错什么了吗?

非常感谢

您需要调用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中首先使用基类

该代码段通过了您的测试,但它很脆,恕我直言,肯定有设计气味。 此外,它还要求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返回一个值或一个集合。 这以不可预测的方式破坏了期望。

  相关解决方案