python - 为什么类在调用类 __init__ 时访问其元类中的变量?

标签 python metaclass

<分区>

r={'a':6} 
c = Myclass(**r) 
out: a 

当我执行 Myclass(**r) 时,这个类从 MyMeta 调用了 fields,而不是从 Myclass。在这个过程中会发生什么?为什么它不使用 Myclass 中的 fields

class MyMeta(type) : 
    def __new__(mcs,name,bases,attr) : 
        fields = {} 
        fields['a'] = 2 
        fields['b'] = 4 
        fields['c'] = 44
        if '__init__' not in attr:
            def init(self,**kwargs): 
                self.api = kwargs.pop('api', None) 
                for k,v in kwargs.items(): 
                     if k in fields : 
                         print(v) 
            attr['__init__'] = init 
        return type.__new__(mcs,name,bases,attr)

class Myclass(metaclass = MyMeta ):
    fields = {'c': 5} 
    def get(self):
        print(4) 

最佳答案

不清楚为什么您需要一个元类,您可能不需要。但为了练习,让我们检查一下它发生了什么。

Python的函数作用域是这样定义的

locals > closure > globals > builtins

永远不会在调用它的范围的命名空间中查找函数。请注意,在这种情况下,即使定义 MyClass.__init__ 也不起作用,因为类方法必须通过属性访问它们的类命名空间。

class SomeClass:
    foo = 0
    def __init__(self):
        self.foo # works
        foo # raises NameError

特别是,这意味着您的 init 方法将在 MyMeta.__new__ 的主体中找到 fields,这是它的闭包。

尽管如此,请注意类的命名空间作为第四个参数传递给 MyMeta.__new__ 方法,此处为 attr。因此,您可以在 MyMeta.__new__ 中的 attr['fields'] 中找到 Myclass.fields

例子

class MyMeta(type):
    def __new__(mcs, name, bases, attr):
        fields = {'foo': 0}

        def init(self, **kwargs):
            print('kwargs:', kwargs)
            print('MyMeta.__new__.fields:', fields)
            print('attr["fields"]:', attr['fields'])

        attr['__init__'] = init
        return type.__new__(mcs, name, bases, attr)


class Myclass(metaclass=MyMeta):
    fields = {'bar': 1}


r = {'baz': 2}
c = Myclass(**r)

输出

kwargs: {'baz': 2}
MyMeta.__new__.fields: {'foo': 0}
attr["fields"]: {'bar': 1}

关于python - 为什么类在调用类 __init__ 时访问其元类中的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55323030/

相关文章:

python - 在没有 math.ceil() 的情况下向上舍入数学计算?

python - 仅实时更新 Dash/plotly 中的数据

swift - 我可以在 Swift 中将元类对象转换为协议(protocol)类型吗?

python - 覆盖父命名空间变量

python - 元类混合或链接?

python - 计算python中的函数链

python - 将两个列表转换为值为列表的字典

python - 如何删除 Squish 事件处理程序?

python - 为什么 Python 的内联类方法与元类定义的方法行为不同

java - 在 Java 中使用 Groovy 向类添加方法