fields['key'] = 'value' started before the metaclass mechanism is started.
class foo(object): var1 = 'bar' def foobar(self): pass
when python gets into the class statement, it enters the new local namespace.
computes the var1 = 'bar' operator. this is equivalent to locals()['var1'] = 'bar'
then computes the def foobar statement. this is equivalent to locals()['var'] = the result of compiling the function
It then passes locals() , as well as the class name, inherited classes, and the metaclass to the __new__ metaclass __new__ . In the case of the example, the metaclass is simply type .
It then exits the new local namespace and places the class object returned from __new__ in an external namespace named foo .
Your code works when you use A.fields because class A has already been created and the above process has been completed with your installation of Meta fields in A
You cannot use super().fields , because the name of the class B not defined to go to super at the time super starts. that is, you need super(B).fields , but B is defined after the class is created.
Update
Here is the code that will do what you want based on your answer to my comment on the question.
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
source share