r={'a':6}
c = Myclass(**r)
out: a
when I executed Myclass(**r), this class called fields from MyMeta, not from Myclass. What happens in this process? Why isn't it using fields from 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)
It's not clear why you need a metaclass here, you probably don't. But for the sake of the exercise, let's examine what it going on.
The scope of Python's function is defined like this
locals > closure > globals > builtins
Never will a function lookup in the namespace of the scope where it was called. Notice that in this case, even defining MyClass.__init__ would not work since class methods must access their class namespace through attributes.
class SomeClass:
foo = 0
def __init__(self):
self.foo # works
foo # raises NameError
In particular, this means your init method will find fields in the body of MyMeta.__new__, which is its closure.
Although, note that the namespace of a class is passed as fourth argument to the MyMeta.__new__ method, here attr. So, you can find Myclass.fields at attr['fields'] in MyMeta.__new__.
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}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With