【问题标题】:Metaclass multiple inheritance inconsistency元类多重继承不一致
【发布时间】:2011-03-01 11:46:18
【问题描述】:

为什么会这样:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyList(list, MyMixin): pass

好的,按预期工作:

created <class '__main__.MyMixin'>
created <class '__main__.MyList'>

但是这个:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyObject(object, MyMixin): pass

不行,就这样炸了?:

created <class '__main__.MyMixin'>
Traceback (most recent call last):
  File "/tmp/junk.py", line 11, in <module>
    class MyObject(object, MyMixin): pass
TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
order (MRO) for bases object, MyMixin

【问题讨论】:

    标签: python metaclass


    【解决方案1】:

    这不是自定义元类问题(尽管它在元类阶段诊断):

    >>> class Normal(object): pass
    ... 
    >>> class MyObject(object, Normal): pass
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Error when calling the metaclass bases
        Cannot create a consistent method resolution
    order (MRO) for bases object, Normal
    

    问题和这个一样:

    >>> class Derived(Normal): pass
    ... 
    >>> class Ok(Derived, Normal): pass
    ... 
    >>> class Nope(Normal, Derived): pass
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Error when calling the metaclass bases
        Cannot create a consistent method resolution
    order (MRO) for bases Normal, Derived
    

    即,不能从基类乘以派生类继承——不可能定义满足通常 MRO 约束/保证的一致 MRO。

    幸运的是,您不想要这样做——子类可能会覆盖基类的某些方法(这就是普通子类的方法;-),并且将基类放在“前面”意味着“掩盖覆盖”。

    将基类放在派生类之后是相当无用的,但至少它是无害的(并且符合正常的 MRO 保证)。

    你的第一个例子当然有效,因为MyMixin 不是list派生的:

    >>> MyMixin.__mro__
    (<class '__main__.MyMixin'>, <type 'object'>)
    

    ...但它派生自object(就像每个现代风格的Python类一样),所以第二个例子不能工作(完全独立于MyMixin有一个自定义元类)。

    【讨论】:

      【解决方案2】:

      这里,你是在继承父类,而父类已经在继承另一个类,所以不需要继承父类已经继承的类。

      例如:

      class A(object):
      .
      .
      class B(object, A):
      .
      .
      

      会报错,因为A继承了Object类,B继承了A,所以间接B继承了object,所以不需要继承object。 . . .

      解决方案是从 B 类 ... 参数列表中删除对象类。

      【讨论】:

        猜你喜欢
        • 2012-06-30
        • 2015-04-27
        • 2023-03-19
        • 2011-09-27
        • 2019-02-05
        • 2015-03-10
        • 1970-01-01
        • 2019-04-14
        相关资源
        最近更新 更多