基类看起来像这样(代码来自Django,但问题不是特定于Django):
class BaseModelForm(BaseForm):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=':',
empty_permitted=False, instance=None):
class ModelForm(BaseModelForm):
__metaclass__ = ModelFormMetaclass
派生类看起来像这样:
class MyForm(forms.ModelForm):
def __init__(self, data=None, files=None, *args, **kwargs):
super(EdocForm, self).__init__(data, files, *args, **kwargs)
self.Meta.model.get_others(data, files, kwargs.get('instance', None))
如果编码器将实例作为kwargs传递,这一切都很好并且应该可以工作,但是如果他们不这样做并将其传递给args呢?在处理* args和** kwargs时,提取实例的有效方法是什么?不可否认,在这种情况下,实例在args中的可能性很小,但如果它是第3个参数而不是第5个参数(不计算自我)。
答案 0 :(得分:1)
在django中,如果实例未通过或未正确设置,则它变为None, init 将为您创建一个新实例 http://docs.nullpobug.com/django/trunk/django.forms.models-pysrc.html#BaseModelForm 但这不是你的问题。 如果未正确设置其他变量,则可能会引发异常。
如果您想检查用户是否正确使用了您的API,那么它真的取决于您,而在python中这可能非常令人生畏,并且检查实例类型并不是非常pythonic,尽管有很多激烈的争论关于拥有如此动态输入的语言是好还是坏的网络。一方面,你可以在动态类型的语言中非常高效,另一方面,你可以有非常讨厌的错误,其解决方案不是那么明显,但这是我自己的经验。
我认为一致性是系统可能拥有的最重要的事情之一,因此我倾向于总是使用关键字值,全部设置为None,然后简单地执行一个断言以确保所需的全部不是None,你可以有一个只检查你的参数是好的功能。根据我自己的经验,关键字参数往往是最灵活的,因为您不需要跟踪订单,您可以通过让被叫方记住其名称来支付价格。
如果你真的需要'实例'那么你可以使用isinstance迭代args和/或kwargs来获取实例变量,尽管我说这不是非常pythonic ....
答案 1 :(得分:0)
如果您坚持接受*args
,处理此情况的一种方法如果instance
对MyForm
很重要,则明确包含instance
}作为MyForm
的关键字参数,将实例添加到kwargs,然后传递kwargs。
class MyForm(forms.ModelForm):
def __init__(self, data=None, files=None, instance=None, *args, **kwargs):
kwargs['instance'] = instance
super(EdocForm, self).__init__(data, files, *args, **kwargs)
请注意,如果有人将实例作为第三个位置参数,则它们会发出非常明确的错误,因为实例是BaseModelForm的最后一个参数。
然而,处理这种情况的更好方法是明确地不允许额外的位置参数。例如:
class MyForm(forms.ModelForm):
def __init__(self, data=None, files=None, **kwargs):
super(EdocForm, self).__init__(data, files, *args, **kwargs)
self.Meta.model.get_others(data, files, kwargs.get('instance', None))
这样,MyForm
只能用最多2个位置参数调用。任何更多和Python解释器将生成TypeError: <func> takes exactly 2 arguments (# given)
。
如果您需要使用instance
参数,则应明确将其包含在MyForm
的关键字参数中。如果做不到这一点,你至少应该在函数的doc字符串中注明它。
如果你是BaseModelForm的子类并且它有一个self.instance
变量,你可以通过super直接访问它。例如。 self.instance = super(EdocForm, self).instance
。这样,你让超类处理它需要做的任何实例,并为自己的后处理抓取实例。 (小心语法与超级...你需要课堂和自我)