我发现我用Python编写的许多类包含一小部分变量,我实际上希望在调用str()
时看到这些变量,并且为每个变量重写__str__(self)
相当麻烦。因此,我煮了以下mixin,
class StrMixin(object):
'''
Automatically generate __str__ and __repr__
'''
def __str__(self):
import types
name = self.__class__.__name__ + ': '
attrs = [ '{}={}'.format(k,v) for (k,v) in self.__dict__.items() ]
return name + ', '.join(attrs)
def __repr__(self):
return str(self)
但是,如果我写一个班级,
class C(object, StrMixin):
pass
我在实例化时收到以下错误,
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases object, StrMixin
当然,包括object
这里是多余的,但这里到底发生了什么?
答案 0 :(得分:11)
定义时:
class StrMixin(object):
...
编译器知道StrMixin
在类的MRO中object
之前。
当你这样做时:
class C(object, StrMixin):
pass
您告诉编译器{1}}在MRO中object
之前。但是StrMixin
也必须在object
之后,所以它必须在MRO中出现两次,这是不允许的。
如果你说:
StrMixin
然后MRO只是class C(StrMixin, object):
pass
,C
,StrMixin
,它满足两个类强加的排序。没有重复,因为尽管object
引用了两次,但定义之间没有冲突。
答案 1 :(得分:1)
您自己回答了问题 - 第二个object
是多余的。 C类有两个基础:object和StrMixin。但是,StrMixin的基础也是对象,所以它首先应该解决它应该解决的对象。 MRO将其计算为(C,STRMixin,object,object),它具有重复的对象。在这种特殊情况下,解决方案应该是显而易见的,但是增加一些类,MRO可能会变得不那么清晰。 E.g。
class A(object):
pass
class B(object, A):
pass
class C(object, A):
pass
class D(object, B, C):
pass
class E(object, A, D):
pass
E的MRO是什么?无论它是什么,它真的很复杂,有重复,可能还有一些循环。
MRO解释得非常好here,你的具体案例大约在页面的三分之二处理,第一个例子是“错误的方法解决方案订单”。
答案 2 :(得分:0)
多重继承可能令人费解。为了在使用mixins时保持简单继承,您可以在类外部定义函数,并在定义时将其分配给类。
class StrMixin: # class here used only as a namespace
@staticmethod # not needed with Python 3
def __str__(self):
name = self.__class__.__name__ + ': '
attrs = [ '{}={}'.format(k,v) for (k,v) in self.__dict__.items() ]
return name + ', '.join(attrs)
__repr__ = __str__
class C(object):
__str__, __repr__ = StrMixin.__str__, StrMixin.__repr__
或者如果您将mixin函数存储在模块中,那么您可以在类中使用它,如下所示:
class C(object):
from StrMixin import __str__, __repr__