我发现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类模块错了!
这是预期的行为吗?
有没有办法覆盖不会引起问题的新?
谢谢,
克里斯托弗
答案 0 :(得分:1)
显然,当元类执行时设置__module__
属性。在您的情况下,元类在m1
内执行。使用正常定义的类,将自动生成__module__
属性并将其传递给元类。但是,您通过手动调用元类创建类,并传入空属性字典。因此,您的类不提供__module__
属性。 __module__
属性是自动创建的,但不会在调用type.__new__
之前创建。由于这发生在模块m1
内,因此当时创建的__module__
引用m1
。
我不确定你为什么要明确地调用元类。元类的重点是允许您自定义使用class
语句定义类时发生的情况。如果你不想使用class
语句,你可以使用常规函数来创建类,而不需要费心去处理元类。
那就是说,我相信你可以通过例如
来获得你想要的行为C11 = C11Meta('C11', (m1.C1,), {'__module__': __name__})