python按类型创建的类的元类

时间:2013-05-21 15:23:32

标签: python oop python-2.7 metaprogramming metaclass

代码优于此处的文字:

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


class A(object):
    __metaclass__ = MetaA

这将打印MetaA

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


B = type('B', (A, ), {'__metaclass__': MetaB})

这将再次打印MetaA(?!)

我希望:

MetaB
MataA

问题是:

  1. 为什么我只获得MetaA
  2. 如何更改代码:

    MetaB
    MataA
    

1 个答案:

答案 0 :(得分:1)

原因是type(name, bases, dict)不是使用指定元类创建类的正确方法。

解释器实际上避免在看到type(name, bases, dict)属性定义时调用__metaclass__,并像通常那样调用mateclass 而不是 type(name, bases, dict)

以下是解释它的相关docs section

  

读取类定义时,如果定义了__元类__   分配给它的callable将被调用而不是type()。这个   允许编写监视或改变的类或函数   课程创建过程[...]

如果您修改代码如下:

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

class A(object):
    __metaclass__ = MetaA


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

class B(A):
    __metaclass__ = MetaB

...然后你会得到预期的输出:

MetaA
MetaB 
MetaA 

(创建A类时打印第一行,创建B类时打印第二行和第三行)

更新:该问题假定动态创建了类B,因此我将扩展我的答案。

要动态构造具有metacalss的类B,您应该像解释器那样做同样的事情,即在__metaclass__ type(name, bases, dict)的{​​{1}}实例中构造具有元类的类。

像这样:

B = MetaB('B', (A, ), {'__metaclass__': MetaB})