1

基类看起来像这样(代码来自 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 中的机会很小,但如果它是第三个参数而不是第五个(不包括自我)。

4

2 回答 2

1

Well in django if instance is not passed or its not properly set then it becomes None and init will then create a new instance for you http://docs.nullpobug.com/django/trunk/django.forms.models-pysrc.html#BaseModelForm But this isn't your question. If the other variables aren't properly set an exception will probably be raised.

Its really up to you if you want to check if the user has properly used your API, and in python this can be quite daunting, and checking for instance types isn't very pythonic, there are very heated debate though out the web about whether its a good or bad thing to have a language thats so dynamically typed. On one hand you can be very productive in a dynamically typed language on the other you can have really nasty bugs whose solution aren't that apparent, but thats from my own experience.

I believe consistency is one of the most crucial things a system could have, as such I tend to always use keyword values, all set to None and then simply do an assert to make sure all that are required aren't None, you could have a function that just checks your parameters are good. Keyword arguments tend to be the most flexible, from my own experience, since you don't need to keep track of the order, you pay the price by having the callee remember its name.

If you really need 'instance' then you can iterate over args and/or kwargs using isinstance to get the instance variable, though like I said this isn't very pythonic....

于 2012-06-09T04:56:55.493 回答
0

如果您坚持接受*args则处理这种情况的一种方法显式包含作为关键字参数,将实例添加到 kwargs,然后传递 kwargs。instanceMyForminstanceMyForm

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)

请注意,如果有人将 instance 作为第三个位置参数,他们将犯一个非常明确的错误,因为 instance 是 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. 如果做不到这一点,您至少应该在函数的文档字符串中记下它。

如果你是 BaseModelForm 的子类并且它有一个self.instance变量,你可以通过 super 直接访问它。例如self.instance = super(EdocForm, self).instance。这样,您就可以让超类处理它需要对实例执行的任何操作,并为自己的后处理获取实例。(注意 super 的语法……你需要 class 和 self)

于 2012-06-09T05:02:06.320 回答