基础元类覆盖__new__生成带有错误__module__的类

时间:2012-06-26 14:23:48

标签: python metaclass

我发现cpython 2.5,2.7,3.2和pypy的奇怪行为,当使用python 2 / python 3兼容的方法使用元类时覆盖__new__的元类:

给定模块m1:

class C1Meta(type):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C1 = C1Meta('C1', (object,), {})


class C2Meta(type):
    pass

C2 = C2Meta('C2', (object,), {})

以下主要计划:

import m1

C10 = m1.C1Meta('C10', (m1.C1,), {})


class C11Meta(m1.C1Meta):
    pass

C11 = C11Meta('C11', (m1.C1,), {})


class C12Meta(m1.C1Meta):
    def __new__(cls, name, bases, dct):
        return m1.C1Meta.__new__(cls, name, bases, dct)

C12 = C12Meta('C12', (m1.C1,), {})


class C13Meta(m1.C1Meta):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C13 = C13Meta('C13', (m1.C1,), {})


C20 = m1.C2Meta('C20', (m1.C2,), {})


class C21Meta(m1.C2Meta):
    pass

C21 = C21Meta('C21', (m1.C2,), {})


class C22Meta(m1.C2Meta):
    def __new__(cls, name, bases, dct):
        return m1.C2Meta.__new__(cls, name, bases, dct)

C22 = C22Meta('C22', (m1.C2,), {})


class C23Meta(m1.C2Meta):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)

C23 = C23Meta('C23', (m1.C2,), {})


print(C10)
print(C11)
print(C12)
print(C13)

print(C20)
print(C21)
print(C22)
print(C23)

运行脚本将产生以下输出(包含所有提到的python版本):

<class 'm1.C10'>
<class 'm1.C11'>
<class 'm1.C12'>
<class '__main__.C13'>
<class '__main__.C20'>
<class '__main__.C21'>
<class '__main__.C22'>
<class '__main__.C23'>

- &GT; C10,C11和C12类模块错了!

这是预期的行为吗?

有没有办法覆盖不会引起问题的

谢谢,

克里斯托弗

1 个答案:

答案 0 :(得分:1)

显然,当元类执行时设置__module__属性。在您的情况下,元类在m1内执行。使用正常定义的类,将自动生成__module__属性并将其传递给元类。但是,您通过手动调用元类创建类,并传入属性字典。因此,您的类不提供__module__属性。 __module__属性是自动创建的,但不会在调用type.__new__之前创建。由于这发生在模块m1内,因此当时创建的__module__引用m1

我不确定你为什么要明确地调用元类。元类的重点是允许您自定义使用class语句定义类时发生的情况。如果你不想使用class语句,你可以使用常规函数来创建类,而不需要费心去处理元类。

那就是说,我相信你可以通过例如

来获得你想要的行为
C11 = C11Meta('C11', (m1.C1,), {'__module__': __name__})