Питон подмешать, чтобы продлить свойство класса
Пытаюсь понять, как написать некоторые миксины для команды управления Django, которые будут обертывать
BaseCommand.option_list
без потери значения текущего класса или любых унаследованных классов / миксинов. Цель состоит в том, чтобы избежать выполнения BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + ( local command options )
в моих командах.
Пример:
class BaseCommmand(object):
option_list = (
# Default options here.
)
# Rest of BaseCommand code.
Я определяю миксин с некоторыми общими вариантами:
class MyCommonOptionMixin(object):
option_list = (
# Some common option/options I wish to have available in many commands
)
def __getattribute__(self, name):
values = super(MyCommonOptionMixin, self).__getattribute__(name)
if name == 'option_list':
for option in self.option_list:
if option not in values:
values += option,
return values
Может быть, у меня есть еще один, просто чтобы покрыть тот случай, когда у меня есть несколько. Оба миксина переопределяют __getattribute__
class MyOtherCommonOptionMixin(object):
option_list = (
# Maybe I have another mixin I want to define separately
)
# Tried this, does not work with more than one mixin.
def __getattribute__(self, name):
values = super(MyOtherCommonOptionMixin, self).__getattribute__(name)
if name == 'option_list':
for option in self.option_list:
if option not in values:
values += option,
return values
# Works if the mixin defines the option_list under a different name, e.g. "_mymixin_options"
# Then access at self._mymixin_options instead of self.option_list
class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand):
option_list = BaseCommand.option_list + (
# Local defined options.
)
Я столкнулся с столкновением, если миксины используйте то же имя для свойства option_list. Есть ли более чистый способ достичь этой цели, чем называть option_list однозначно внутри микшинов и переопределять __getattribute__
?
1 ответ:
Совет в документации состоит в том, чтобы явно объединить различные списки опций. Тем не менее, если вы хотите пойти этим путем, я думаю, что пользовательский метакласс-это правильный подход. Что-то вроде:
class CommandMetaclass(type): def __new__(mcl, name, bases, dct): # start with the option_list in the class we're creating # use set() to avoid duplicates option_list = set(dct.get('option_list', tuple())) # add the options from each base class for base in bases: option_list.update(base.__dict__.get('option_list', tuple())) # replace the original option_list with our combined version dct['option_list'] = tuple(option_list) return type.__new__(mcl, name, bases, dct) class MyCommand(MyCommonOptionMixin, MyOtherCommonOptionMixin, BaseCommand): __metaclass__ = CommandMetaclass option_list = ( # Local defined options. )