当类的元类是其子类的元类的子类时,一切都发生了?

时间:2018-01-11 16:38:57

标签: python inheritance metaclass cpython

它是关于Python2.7中的元类。

要清楚,代码如下:

class MetaC(type):
    def __new__(cls, name, bases, attrs):
        print "MetaC"
        return super(MetaC, cls).__new__(cls, name, bases, attrs)

class MetaB(MetaC):
    def __new__(cls, name, bases, attrs):
        print "MetaB"
        return super(MetaB, cls).__new__(cls, name, bases, attrs)

class MetaA(MetaB):
    def __new__(cls, name, bases, attrs):
        print "MetaA"
        return super(MetaA, cls).__new__(cls, name, bases, attrs)

class A(object):
    __metaclass__ = MetaA

print type(A)

class B(A):
    __metaclass__ = MetaB

print type(B)

class C(B):
    __metaclass__ = MetaC

print type(C)

结果如下:

MetaA
MetaB
MetaC
<class '__main__.MetaA'>
MetaB
MetaC
MetaA
MetaB
MetaC
<class '__main__.MetaA'>
MetaC
MetaA
MetaB
MetaC
<class '__main__.MetaA'>

似乎在创建课程C时,MetaA.__new__之后会调用MetaC.__new__

为了解决这个问题,我查看了源代码并找到了typeobject.c

static PyObject *
type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
{
    /* some code is omitted here */
    for (i = 0; i < nbases; i++) {
        tmp = PyTuple_GET_ITEM(bases, i);
        tmptype = tmp->ob_type;
        if (tmptype == &PyClass_Type)
            continue; /* Special case classic classes */
        if (PyType_IsSubtype(winner, tmptype))
            continue;
        if (PyType_IsSubtype(tmptype, winner)) {
            winner = tmptype;
            continue;
        }
        PyErr_SetString(PyExc_TypeError,
                        "metaclass conflict: "
                        "the metaclass of a derived class "
                        "must be a (non-strict) subclass "
                        "of the metaclasses of all its bases");
        return NULL;
    }
    if (winner != metatype) {
        if (winner->tp_new != type_new) /* Pass it to the winner */
            return winner->tp_new(winner, args, kwds);
        metatype = winner;
    }
    /* some code is omitted here */
}

for循环找到最深的子类winner(抱歉我的英文不好,代码可能比我的文字清晰得多)。如果不是metatype,则会调用winner->tp_new。这就是我从我的代码中得到结果的原因。

所以,我想知道的是,为什么它的设计是这样的?是否有任何实用的案例表明这样做的必要性?

另外,我还注意到了错误消息

  

元类冲突:派生类的元类必须是其所有基类的元类的(非严格)子类

显然,就我而言,C的元类MetaC不是其基类的任何元类的子类。那么,它是一个非STRICT子类吗? “非严格”在这里意味着什么?

1 个答案:

答案 0 :(得分:0)

当然,你提出的具体案例是最虚构的。

对于给定的类层次结构(从A继承的B),必须存在A和B的元类的特征才能正确创建B.并且有一种方法可以合理地确定B的元类也如果B的元类是A的元类的子类,那么它包含了A所做的任何元类。

在更现实的场景中,您可以拥有一个专门用于元类的层次结构树,而在树上,在多继承场景中,人们会希望类“G”的元类包含各种各样的内容。它继承的分支。

它实际上是唯一有意义的设计 - 即使它是如此的角落情况,它几乎从未到达。你是一个完全人为的例子来强调这个角落的情况,它刚刚解决了。

对于你的例子,

改述,当在那里实例化你的“C”类时,这意味着虽然你的“C”,作为子类也是“B”和“A”,初始化“B”和“A”时,需要运行的代码不会运行。

对于另一个问题“非严格子类”,它意味着派生元类可以使用多重继承,并且是其父元类的子类,而不是父类的元类,如果它们也从父类的元类继承。