按类型创建的类的python元类

Posted

技术标签:

【中文标题】按类型创建的类的python元类【英文标题】:python metaclasses of classes created by type 【发布时间】:2013-05-16 10:28:40 【问题描述】:

这里的代码胜过文字:

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

问题是:

    为什么我只收到MetaA

    如何更改代码获取:

    MetaB
    MataA
    

【问题讨论】:

【参考方案1】:

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

解释器实际上避免在看到__metaclass__ 属性定义并调用mateclass 而不是 type(name, bases, dict) 时调用type(name, bases, dict),因为它通常会这样做。

这里是相关的docs section 解释它:

读取类定义时,如果定义了__元类__则 分配给它的可调用对象将被调用而不是 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__ instad of type(name, bases, dict) 中的元类构造类。

像这样:

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

【讨论】:

你说对了一部分,但你没有抓住重点。我使用“类型”的原因是因为我有很多想要动态创建的类。但是由于 'type' 是元类,应该写 MetaB('B', (A, ), 'metaclass': MetaB) 而不是 type('B', (A, ), ' 元类':元B)。我昨天已经想通了。如果您更改答案以反映我的要求(动态创建的类),我会接受您的回答。 @mnowotka 啊,明白了。这就是您首先使用type 的原因。我已经更新了答案。

以上是关于按类型创建的类的python元类的主要内容,如果未能解决你的问题,请参考以下文章

1104课堂小结

面向对象之元类

python元类深入解析

096 元类

python 吐血总结面向对象元类

python 吐血总结面向对象元类