开发者

Dynamically add base class?

开发者 https://www.devze.com 2023-01-05 19:05 出处:网络
Let\'s say I have开发者_高级运维 a base class defined as follows: class Form(object): class Meta:

Let's say I have开发者_高级运维 a base class defined as follows:

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

Now a developer comes a long and defines his subclass like:

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

Now suddenly the method attribute is lost. How can I "get it back" without forcing the user to inherit his meta class from mine? Can I dynamically add a base class to Form.Meta in the initializer, or in a metaclass's __new__ func?


As long as they won't override your __init__, or it will be called (ie by super), you can monkey-patch the Meta inner class:

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'


Do you really need Meta to be defined that way? If you only need to access it as form.Meta.method, why wouldn't you just use a dotdict?

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

Then you can do this:

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'


Maybe you could use a metaclass like this:

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

The code is really simple and maybe you need to suit it to your needs.


You can check for method attribute in the __init__ method of a parent object and update it if needed. Of course this will work only if the programmer you are protecting your code from will call it in his constructor.

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'


Maybe I could omit the default Meta class inside Form and use a default dict instead?

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号