fields['key'] = 'value'
запускается до запуска механизма метакласса.
class foo(object):
var1 = 'bar'
def foobar(self):
pass
, когда python выполняет оператор class
, он входит в новое локальное пространство имен.
оценивает оператор var1 = 'bar'
.это эквивалентно locals()['var1'] = 'bar'
, затем оно вычисляет оператор def foobar
.это эквивалентно locals()['var'] = the result of compiling the function
Это , затем передает locals()
вместе с именем класса, унаследованными классами и метаклассом метаклассу __new__
методу,В этом примере метакласс просто type
.
Затем он выходит из нового локального пространства имен и вставляет объект класса, возвращенный из __new__
, во внешнее пространство имен с именем foo
.
Ваш код работает, когда вы используете A.fields
, потому что класс A
уже создан и, следовательно, вышеописанный процесс был выполнен с вашей Meta
установкой fields
in A
.
Вы не можете использовать super().fields
, потому что имя класса B
не определено для передачи super в момент запуска super.то есть вам нужно, чтобы оно было super(B).fields
, но B
определено после создания класса.
Update
Вот код, который будет делать то, что вы хотитеосновываясь на вашем ответе на мой комментарий к вопросу.
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