Позвольте мне начать с определения целей, у меня есть:Применение правил метакласса ко всем потомкам, а не прямой metaclassed класса
Включение определения абстрактных членов класса (не свойства, методы или члены экземпляра), не по умолчанию значения (не None или какое-либо другое магическое значение, но бросание ошибки, если не реализовано).
На службе (1), создавая многоразовый абстрактный механизм, который делает создание классов с абстрактными членами тривиальными, а код - максимально кратким.
Имея возможность присоединить абстрактные члены класса к родительскому классу (в качестве подкласса, метакласса или любым другим способом), где абстрактные члены не должны определяться до тех пор, пока не будет определен конкретный подкласс.
То, что я получил до сих пор:
metaclass_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
(ex if 'Abstract' not in name
), но это кажется язвительным и хрупким.
Есть ли лучший способ сделать это?
Да, есть лучший способ. Используйте [ABC module] (http://docs.python.org/library/abc.html) из стандартной библиотеки Python. – agf
@agf, кроме того, что я понимаю, это допускает только абстрактные методы и свойства, а не абстрактные члены класса. –