其他分享
首页 > 其他分享> > 调用类__init__时,为什么类从其元类访问变量?

调用类__init__时,为什么类从其元类访问变量?

作者:互联网

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

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

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__的主体中找到字段,这是它的闭包.

虽然,请注意,将类的名称空间作为第四个参数传递给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}

标签:metaclass,python
来源: https://codeday.me/bug/20191211/2105538.html