Функциональность метакласса на всех наследников, исключая базовый класс
У меня в приложении есть класс для наследования остальных подклассов. Одна из его задач в том, что он передаёт генерацию класса своему метаклассу, чтобы кроме наследования не нужно было дополнительно прописывать metaclass=SmthMeta.
class ClassesMeta(type):
def __new__(mcs, clsname, bases, dct):
dct['b'] = dct.get('a', 0) + 10
return super(ClassesMeta, mcs).__new__(mcs, clsname, bases, dct)
class Base(metaclass=ClassesMeta):
a = 5
class Child(Base):
a = 10
Base.b # 15
Child.b # 20
Но проблема в том, что в логике моего приложения класс Base должен иметь атрибут a = None, но всегда имеет переопределённый атрибут у детей, а также класс Base никогда не используется кроме как для наследования.
Но код
class Base(metaclass=ClassesMeta):
a = None
class Child(Base):
a = 10
ожидаемо выдаст ошибку во время инициализации Base:
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
class Base(metaclass=ClassesMeta):
File "<pyshell#1>", line 3, in __new__
dct['b'] = dct.get('a', 0) + 10
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Итого: мне нужно сделать применение метакласса не непосредственно к классу с metaclass=ClassesMeta, а ко всем, наследованным от него. Пока что моё решение в том, чтобы фильтровать имя класса:
class ClassesMeta(type):
def __new__(mcs, clsname, bases, dct):
if clsname == 'Base':
return type.__new__(mcs, clsname, bases, dct)
dct['b'] = dct.get('a', 0) + 10
return super(ClassesMeta, mcs).__new__(mcs, clsname, bases, dct)
Но это выглядит как большой костыль. Есть ли способ убрать для Base генерацию атрибута b более правильным способом?
Ответы (1 шт):
Ошибка у Вас в том что метод get для словаря вернет значение по умолчанию если ключа не существует, а он есть просто равен None.
class ClassesMeta(type):
def __new__(mcs, clsname, bases, dct):
val = dct.get('a', 0)
if val is None:
val = 0
dct['b'] = val + 10
return super(ClassesMeta, mcs).__new__(mcs, clsname, bases, dct)