Python mixin to extend class property
django, metaclass, mixins, multiple-inheritance, python
Solution
The advice in the documentation is to explicitly concatenate the various option lists. That said, if you want to go this route I think a custom metaclass is the right approach. Something like:
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.
)
Problem
Trying to figure out how to write some mixins for Django management command that will wrap the `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 a mixin with some common options: ``` 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 that case where I have multiple. The mixins both override `__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. ) ``` I've run into collision if the mixins use the same name for the option_list property. Is there a cleaner way to achieve this goal than naming the option_list uniquely inside the mixins and overriding `__getattribute__`?