Позвольте мне начать с определения целей, которые у меня есть:
Включение определения членов абстрактного класса (не свойств, методов или членов экземпляра) без значений по умолчанию (не None или какое-либо другое магическое значение, но выдает ошибку, если оно не реализовано).
На службе (1) создание повторно используемого абстрактного механизма, который делает создание классов с абстрактными членами тривиальным, а код для этого максимально лаконичным.
Наличие возможности присоединять члены абстрактного класса к родительскому классу (в качестве подкласса, метакласса или любым другим способом), где абстрактные члены не нужно определять до тех пор, пока не будет определен конкретный подкласс.
Что у меня есть до сих пор:
метакласс_lib.py:
class AbstractRequiredClassMembersMetaclass(type):
def __new__(cls, name, bases, attrs):
missed_members = []
for class_member in cls.REQUIRED_CLASS_MEMBERS:
if class_member not in attrs:
missed_members.append(class_member)
if missed_members:
raise NotImplementedError('Class missing required members %s.' % missed_members)
return super(AbstractRequiredClassMembersMetaclass, cls).__new__(cls, name, bases, attrs)
class _MakeRequiredClassMemebersMetaclass(object):
existing_classes = {}
def __call__(self, name, required_members):
if name in _MakeRequiredClassMemebersMetaclass.exisiting_classes:
if required_members != _MakeRequiredClassMemebersMetaclass.exisiting_classes[name].REQUIRED_CLASS_MEMBERS:
raise RuntimeError('Class of name %s already defined with different required_members.' % name)
else:
NewClass = type(name, (AbstractRequiredClassMembersMetaclass,), {'REQUIRED_CLASS_MEMBERS' : required_members})
_MakeRequiredClassMemebersMetaclass.exisiting_classes[name] = NewClass
return _MakeRequiredClassMemebersMetaclass.exisiting_classes[name]
make_required_class_members_metaclass = _MakeRequiredClassMemebersMetaclass()
goods.py (реализация для иллюстрации):
from metaclass_lib import make_required_class_members_metaclass
class AbstractGood(object):
__metaclass__ = make_required_class_members_metaclass('AbstractGoodMeta', ('unit_measure',))
def __init__(self):
self.unit_price = None
def total_cost(self, number_of_units):
return self.unit_price * self.number_of_units
class DeliGood(AbstractGood):
unit_measure = 'lbs'
def __init__(self):
self.sandwich_counter_product = False
class RefridgeratedGood(AbstractGood):
unit_measure = 'package'
def __init__(self):
self.freezer_safe = False
self.optimal_temp = '35'
Это не работает, потому что метакласс задыхается во время создания объекта AbstractGood
type
. Проблема в том, что я хочу, чтобы все конкретные товары определяли член класса, но я не хочу определять член класса ни в одной из абстрактных баз. Все, о чем я могу думать, это заставить метакласс выполнять проверку in attrs
только в том случае, если ключевое слово не находится в name
(например, if 'Abstract' not in name
), но это кажется дерганым и хрупким.
Есть лучший способ сделать это?