代码之家  ›  专栏  ›  技术社区  ›  Matt Anderson

元类多重继承不一致

  •  56
  • Matt Anderson  · 技术社区  · 14 年前

    为什么会这样:

    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
    
    2 回复  |  直到 8 年前
        1
  •  82
  •   Alex Martelli    14 年前

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

    >>> 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类一样),因此第二个示例无法工作(完全独立于 莫米辛 具有自定义元类)。

        2
  •  -1
  •   Peter Mortensen Josh McGee    8 年前

    这里,您正在继承父类,父类已经继承了另一个类,因此不需要继承父类已经继承的类。

    例如:

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

    它将引发一个错误,因为a正在继承类对象,b正在继承a,因此间接b正在继承对象,因此不需要继承对象。 . . .

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