python:元类中__new__的调用时机
下面的代码无法编译,它提示:
NameError: name 'fields' is not defined
在最后一行。是不是因为 __new__
这个方法要等到 fields
赋值后才被调用?我该怎么办呢?
class Meta(type):
def __new__(mcs, name, bases, attr):
attr['fields'] = {}
return type.__new__(mcs, name, bases, attr)
class A(metaclass = Meta):
def __init__(self, name):
pass
class B(A):
fields['key'] = 'value'
补充:
我发现这不是时间上的问题,而是名字隐藏的问题。如果我直接写 A.fields
,就没问题了。
我想知道为什么我不能使用 fields
或者 super().fields
。
1 个回答
4
在执行 fields['key'] = 'value'
这行代码之前,元类的机制还没有开始工作。
class foo(object):
var1 = 'bar'
def foobar(self):
pass
当 Python 遇到 class
这个声明时,它会进入一个新的局部命名空间。
首先,它会执行
var1 = 'bar'
这行代码。这相当于locals()['var1'] = 'bar'
。接着,它会执行
def foobar
这行代码。这相当于locals()['var'] = 编译函数的结果
。然后,它会把
locals()
、类名、继承的类和元类一起传给元类的__new__
方法。在这个例子中,元类就是type
。最后,它会退出这个新的局部命名空间,把从
__new__
返回的类对象放到外部命名空间中,并命名为foo
。
当你使用 A.fields
时,代码是可以工作的,因为类 A
已经被创建,以上的过程也已经执行过,你的 Meta
在 A
中安装了 fields
。
你不能使用 super().fields
,因为类名 B
在 super 运行时还没有定义。也就是说,你需要用 super(B).fields
,但 B
是在类创建之后才定义的。
更新
这里有一些代码,可以根据你对我评论的回复来实现你想要的功能。
def MakeFields(**fields):
return fields
class Meta(type):
def __new__(mcs, name, bases, attr):
for base in bases:
if hasattr(base, 'fields'):
inherited = getattr(base, 'fields')
try:
attr['fields'].update(inherited)
except KeyError:
attr['fields'] = inherited
except ValueError:
pass
return type.__new__(mcs, name, bases, attr)
class A(metaclass=Meta):
fields = MakeFields(id='int',name='varchar')
class B(A):
fields = MakeFields(count='int')
class C(B):
pass
class Test(object):
fields = "asd"
class D(C, Test):
pass
print C.fields
print D.fields