Динамически добавить базовый класс? - PullRequest
2 голосов
/ 03 июля 2010

Допустим, у меня есть базовый класс, определенный следующим образом:

class Form(object):
    class Meta:
        model = None
        method = 'POST'

Теперь разработчик приходит долго и определяет свой подкласс как:

class SubForm(Form):
    class Meta:
        model = 'User'

Теперь внезапно атрибут method теряется. Как я могу "вернуть его", не заставляя пользователя наследовать свой метакласс от моего? Могу ли я динамически добавить базовый класс к Form.Meta в инициализаторе или в __new__ func метакласса?

Ответы [ 5 ]

9 голосов
/ 13 июля 2010

Пока они не переопределят ваш __init__, или он будет вызван (то есть super), вы можете обезопасить внутренний класс Meta:

class Form(object):
    class Meta:
        model = None
        method = "POST"

    def __init__(self, *args, **kwargs):
        if self.__class__ != Form:
            self.Meta.__bases__ += (Form.Meta,)
        # other __init__ code here.

class SubForm(Form):
    class Meta:
        model = 'User'
4 голосов
/ 14 июля 2010

Вам действительно нужно, чтобы мета была определена таким образом?Если вам нужно получить доступ к нему как form.Meta.method, почему бы вам просто не использовать дотдикт?

class dotdict(dict):
    def __getattr__(self, attr):
        return self.get(attr, None)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

Тогда вы можете сделать это:

class Form(object):
    def __init__(self):
        self.Meta = dotdict()
        self.Meta.model = None
        self.Meta.method = 'POST'

class SubForm(Form):
    def __init__(self):
        Form.__init__(self)
        self.Meta.model = 'User'
1 голос
/ 15 июля 2010

Может быть, вы могли бы использовать метакласс как этот:

class _Meta:
    model = None
    method = "Post"

class MetaForm(type):

    def __init__(cls, name, bases, dct):
        super(MetaForm, cls).__init__(name, bases, dct)
        if hasattr(cls, 'Meta'):            
            meta = getattr(cls, 'Meta')                
            for k,v in _Meta.__dict__.items():
                check = meta.__dict__.get(k)
                if not check:
                    meta.__dict__[k] = v    
        else:
            setattr(cls, "Meta", _Meta)        


class Form(object):
    __metaclass__ = MetaForm

class SubForm(Form):
    class Meta:
        model = 'User'

class Sub2Form(Form):
    pass

sub_form = SubForm()        
sub2_form = Sub2Form()    

print sub_form.Meta.method # prints "Post"
print sub2_form.Meta.model # prints None

Код действительно прост, и, возможно, вам нужно соответствовать его вашим потребностям.

1 голос
/ 12 июля 2010

Вы можете проверить атрибут метода в методе __init__ родительского объекта и обновить его при необходимости.Конечно, это будет работать, только если программист, от которого вы защищаете свой код, вызовет его в своем конструкторе.

class Form(object):
    def __init__(self):
            if not getattr(self.Meta,'method',False):
                    self.Meta.method='POST'
    class Meta:
       model = None
       method = 'POST'

class SubForm(Form):
    class Meta:
       model = 'User'
0 голосов
/ 06 июля 2010

Может быть, я мог бы опустить класс Meta по умолчанию внутри Form и использовать вместо него dict по умолчанию?

meta_defaults = {'model':None, 'method':'POST'}
meta_vars = meta_defaults
meta_vars.update(Form.Meta.__dict__)
...