python:元类中 __new__ 的计时
以下代码无法编译;它说
NameError:名称“字段”不是 定义
在最后一行 。是因为在达到 fields
赋值之后才调用 __new__
吗?我应该怎么办?
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
。
The following code doesn't compile; it says
NameError: name 'fields' is not
defined
in the last line. Is it because __new__
isn't called until after the fields
assignment is reached? What should I do?
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'
EDIT:
I found that it's not a problem with timing; it's a problem with name hiding. Works fine if I write A.fields
instead.
I'd like to know why I can't use fields
or super().fields
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
fields['key'] = 'value'
在元类机制启动之前运行。当 python 命中
class
语句时,它会进入一个新的本地命名空间。它评估
var1 = 'bar'
语句。这相当于locals()['var1'] = 'bar'
然后它会计算
def foobar
语句。这相当于locals()['var'] = 编译函数的结果
,
它then传递
locals()
,连同类名、继承类和元类到元类__new__
方法。在示例中,元类只是type
。然后,它退出新的本地命名空间,并将从
__new__
返回的类对象粘贴到名为foo
的外部命名空间中。当您使用
A.fields
时,您的代码可以工作,因为类A
已经创建,因此上述过程已在安装Meta
时执行A
中的字段
。您不能使用
super().fields
,因为类名B
未定义为在 super 运行时传递给 super。也就是说,您需要它是super(B).fields
但B
是在类创建之后定义的。更新
这里有一些代码可以根据您对我对问题的评论的回复来执行您想要的操作。
The
fields['key'] = 'value'
runs before the metaclass machinery kicks in.when python hits the
class
statement, it enters a new local namespace.it evaluates the
var1 = 'bar'
statement. this is equivalent tolocals()['var1'] = 'bar'
it then evaluates the
def foobar
statement. this is equivalent tolocals()['var'] = the result of compiling the function
It then passes
locals()
, along with the classname, the inherited classes and the metaclass to the metaclasses__new__
method. In the example case, the metaclass is simplytype
.It then exits the new local namespace and sticks the class object returned from
__new__
in the outer namespace with the namefoo
.Your code works when you use
A.fields
because the classA
has already been created and the above process has hence been executed with yourMeta
installingfields
inA
.You can't use
super().fields
because the classnameB
is not defined to pass to super at the time that super would run. that is that you would need it to besuper(B).fields
butB
is defined after class creation.Update
Here's some code that will do what you want based on your reply to my comment on the question.