2012-05-23 1 views
1

Позвольте мне начать с определения целей, у меня есть:Применение правил метакласса ко всем потомкам, а не прямой metaclassed класса

  1. Включение определения абстрактных членов класса (не свойства, методы или члены экземпляра), не по умолчанию значения (не None или какое-либо другое магическое значение, но бросание ошибки, если не реализовано).

  2. На службе (1), создавая многоразовый абстрактный механизм, который делает создание классов с абстрактными членами тривиальными, а код - максимально кратким.

  3. Имея возможность присоединить абстрактные члены класса к родительскому классу (в качестве подкласса, метакласса или любым другим способом), где абстрактные члены не должны определяться до тех пор, пока не будет определен конкретный подкласс.

То, что я получил до сих пор:

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' 

Это не потому что метаклассы дросселируют во время создания объекта AbstractGoodtype. Проблема в том, что я хочу, чтобы все конкретные товары определяли член класса, но я не хочу определять член класса в любой из абстрактных баз. Все, что я могу придумать, - это иметь метаклассу, только если in attrs проверить, нет ли ключевого слова в name (ex if 'Abstract' not in name), но это кажется язвительным и хрупким.

Есть ли лучший способ сделать это?

+0

Да, есть лучший способ. Используйте [ABC module] (http://docs.python.org/library/abc.html) из стандартной библиотеки Python. – agf

+0

@agf, кроме того, что я понимаю, это допускает только абстрактные методы и свойства, а не абстрактные члены класса. –

ответ

1

Также взломанный, но более надежный, чем проверка имени. Вы знаете, что базовый базовый класс не имеет базовых классов (или имеет только object тип в python 2). Поэтому вы можете это проверить :)

class AbstractBase(object): 
    class __metaclass__(type): 
     def __new__(mcs, name, bases, dict_): 
      if bases[0] is not object: # hack to not apply these on AbstractBase 
       assert 'unit_measure' in dict_ 
      return type.__new__(mcs, name, bases, dict_) 


class DeliGood(AbstractBase): 
    unit_measure = 'lbs' 
Смежные вопросы