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__)
精彩评论