用于__str__和方法解析顺序的Python Mixin

时间:2012-03-09 09:30:03

标签: python mixins

我发现我用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这里是多余的,但这里到底发生了什么?

3 个答案:

答案 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 CStrMixin,它满足两个类强加的排序。没有重复,因为尽管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__