如何动态添加 mixin 作为基类而不会出现 MRO 错误? [英] How do I dynamically add mixins as base classes without getting MRO errors?

查看:25
本文介绍了如何动态添加 mixin 作为基类而不会出现 MRO 错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个 ABC 类.

Say I have a class A, B and C.

Class AB 都是 Class C 的 mixin 类.

Class A and B are both mixin classes for Class C.

class A( object ):
    pass
class B( object ):
    pass
class C( object, A, B ):
    pass

这在实例化 C 类时不起作用.我必须从 C 类中删除 object 才能使其工作.(否则你会遇到 MRO 问题).

This will not work when instantiating class C. I would have to remove object from class C to make it work. (Else you'll get MRO problems).

TypeError: 调用元类基时出错
无法创建一致的方法解析
订单(MRO)为基地B,对象,A

TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases B, object, A

不过,我的情况有点复杂.在我的例子中,C 类是一个 服务器,其中 AB 将是在启动时加载的插件.这些文件位于它们自己的文件夹中.

However, my case is a bit more complicated. In my case class C is a server where A and B will be plugins that are loaded on startup. These are residing in their own folder.

我还有一个名为 Cfactory 的类.在 Cfactory 中,我有一个 __new__ 方法可以创建一个功能齐全的对象 C.在 __new__ 方法中,我 search 寻找插件,使用 __import__,然后将它们赋值给 C.__bases__ += (loadedClassTypeGoesHere, )

I also have a Class named Cfactory. In Cfactory I have a __new__ method that will create a fully functional object C. In the __new__ method I search for plugins, load them using __import__, and then assign them to C.__bases__ += (loadedClassTypeGoesHere, )

所以以下是一种可能性:(让它变得很抽象)

So the following is a possibility: (made it quite abstract)

class A( object ):
    def __init__( self ): pass
    def printA( self ):   print "A"
class B( object ):
    def __init__( self ): pass
    def printB( self ):   print "B"
class C( object ):
    def __init__( self ):  pass
class Cfactory( object ):
    def __new__( cls ):
        C.__bases__ += ( A, )
        C.__bases__ += ( B, )
        return C()

这再次不起作用,并且会再次出现 MRO 错误:

This again will not work, and will give the MRO errors again:

类型错误:无法创建一致的方法解析
基础对象的订单(MRO),A

TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A

一个简单的解决方法是从 AB 中删除 object 基类.然而,这将使它们成为旧式对象,当这些插件独立运行时应避免使用这些对象(这应该是可能的,UnitTest 明智的)

An easy fix for this is removing the object baseclass from A and B. However this will make them old-style objects which should be avoided when these plugins are being run stand-alone (which should be possible, UnitTest wise)

另一个简单的解决方法是从 C 中删除 object 但这也将使其成为旧式类并且 C.__bases__ 将不可用因此我不能在 C

Another easy fix is removing object from C but this will also make it an old-style class and C.__bases__ will be unavailable thus I can't add extra objects to the base of C

对此有什么好的架构解决方案,您将如何做这样的事情?现在,我可以使用插件本身的旧式类.但我宁愿不使用它们.

What would be a good architectural solution for this and how would you do something like this? For now I can live with old-style classes for the plugins themselves. But I rather not use them.

推荐答案

这样想——你希望 mixin 覆盖 object 的一些行为,所以它们需要在object 在方法解析顺序中.

Think of it this way -- you want the mixins to override some of the behaviors of object, so they need to be before object in the method resolution order.

所以你需要改变碱基的顺序:

So you need to change the order of the bases:

class C(A, B, object):
    pass

由于这个bug,你需要C不要直接从对象继承才能正确分配给 __bases__,并且工厂真的可以只是一个函数:

Due to this bug, you need C not to inherit from object directly to be able to correctly assign to __bases__, and the factory really could just be a function:

class FakeBase(object):
    pass

class C(FakeBase):
    pass

def c_factory():
    for base in (A, B):
        if base not in C.__bases__:
            C.__bases__ = (base,) + C.__bases__
    return C()

这篇关于如何动态添加 mixin 作为基类而不会出现 MRO 错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆