如何动态添加 mixin 作为基类而不会出现 MRO 错误? [英] How do I dynamically add mixins as base classes without getting MRO errors?
问题描述
假设我有一个 A
、B
和 C
类.
Say I have a class A
, B
and C
.
Class A
和 B
都是 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
类是一个 服务器,其中 A
和 B
将是在启动时加载的插件.这些文件位于它们自己的文件夹中.
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
一个简单的解决方法是从 A
和 B
中删除 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屋!