2014-03-25 4 views
6

BaseCommand.option_list 래핑하는 Django 관리 명령에 대한 몇 가지 mixins 작성 방법을 알아 내려고 현재 클래스 또는 상속 된 클래스/mixins 값을 잃지 않고. 목표는 내 명령에 BaseCommand.option_list + MyCommonOptionMixin.option_list + MyOtherCommonOptionMixin.option_list + (local command options)을하지 않는 것입니다.파이썬 mixin 클래스 속성을 확장하는

예 :

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 

어쩌면 난 그냥 여러있는 경우를 충당하기 위해, 하나 더 있습니다

class BaseCommmand(object): 
    option_list = (
     # Default options here. 
    ) 

    # Rest of BaseCommand code. 

나는 몇 가지 일반적인 옵션이있는 믹스 인을 정의합니다. 유지 mixin이 option_list 속성에 같은 이름을 사용하는 경우 유지 mixin 모두 재정의 __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. 
    ) 

나는 충돌로 실행했습니다. mixin 내에서 option_list를 고유하게 지정하고 __getattribute__을 무시하는 것보다이 목표를 달성하는 더 깨끗한 방법이 있습니까?

답변

5

documentation의 조언은 다양한 옵션 목록을 명시 적으로 연결하는 것입니다. 즉,이 경로를 가고 싶다면 사용자 지정 메타 클래스가 올바른 접근이라고 생각합니다. 다음과 같음 :

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. 
    )