Python mixin to extend class property

Trying to figure out how to write multiple mixins for a Django control command that will wrap BaseCommand.option_list without losing the value of the current class or any inherited classes / mixins. The goal is to avoid doing BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + ( local command options ) in my commands.

Example:

 class BaseCommmand(object): option_list = ( # Default options here. ) # Rest of BaseCommand code. 

I define mixin with some common parameters:

 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 

Maybe I have one more, just to cover the case when I have a lot. Mixins redefine __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, eg "_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. ) 

I ran into a conflict if mixins use the same name for the option_list property. Is there a cleaner way to achieve this than the unique identifier option_list inside mixins and overriding __getattribute__ ?

+6
source share
1 answer

The advice in the documentation is to explicitly concatenate the various option lists. However, if you want to go this route, I think the usual metaclass is the right approach. Sort of:

 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. ) 
+5
source

All Articles