4

以下代码无法编译;它说

NameError:名称“字段”未定义

在最后一行。是因为直到分配__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

我想知道为什么我不能使用fieldsor super().fields

4

1 回答 1

4

fields['key'] = 'value'元类机器启动之前的运行。

class foo(object):
    var1 = 'bar'

    def foobar(self):
        pass

当 python 命中该class语句时,它会进入一个新的本地命名空间。

  1. 它评估var1 = 'bar'语句。这相当于locals()['var1'] = 'bar'

  2. 然后它评估该def foobar语句。这相当于locals()['var'] = the result of compiling the function

  3. 然后locals()连同类名、继承的类和元类一起传递给元类 方法__new__。在示例中,元类是简单的type

  4. __new__然后它退出新的本地命名空间并将从外部命名空间返回的类对象与 name 粘贴在一起foo

您的代码在您使用时有效,因为已经创建A.fields了该类,因此上述过程已在您的安装中执行。AMetafieldsA

您不能使用super().fields,因为类名B未定义为在 super 运行时传递给 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
于 2010-09-16T06:05:10.403 回答