【问题标题】:What is a simple way to deal with argument initial in (*args, **kwargs) python?在 (*args, **kwargs) python 中处理参数初始值的简单方法是什么?
【发布时间】:2012-06-09 04:00:53
【问题描述】:

基类看起来像这样(代码来自 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 时,提取 instance 的明智方法是什么?诚然,在这种情况下,实例在 args 中的机会很小,但如果它是第三个参数而不是第五个(不包括 self)。

【问题讨论】:

    标签: python


    【解决方案1】:

    在 django 中,如果实例未通过或未正确设置,则它变为 None 并且 init 将为您创建一个新实例 http://docs.nullpobug.com/django/trunk/django.forms.models-pysrc.html#BaseModelForm 但这不是你的问题。 如果未正确设置其他变量,则可能会引发异常。

    如果您想检查用户是否正确使用了您的 API,这完全取决于您,而在 python 中,这可能会非常令人生畏,而且检查实例类型并不是非常符合 python 的,尽管目前存在非常激烈的争论web 关于拥有如此动态类型的语言是好事还是坏事。一方面,您可以在动态类型语言中非常高效,另一方面,您可能会遇到非常讨厌的错误,其解决方案并不那么明显,但这是我自己的经验。

    我相信一致性是系统可能拥有的最重要的东西之一,因此我倾向于总是使用关键字值,全部设置为 None,然后简单地做一个断言来确保所有需要的不是 None,你可以有一个函数来检查你的参数是否良好。根据我自己的经验,关键字参数往往是最灵活的,因为你不需要跟踪订单,你需要让被调用者记住它的名字来付出代价。

    如果您真的需要“实例”,那么您可以使用 isinstance 遍历 args 和/或 kwargs 以获取实例变量,尽管就像我说的那样,这不是很 Pythonic....

    【讨论】:

    • 是的,这就是我的想法。我希望有人有这样做的pythonic方法。 getarg('instance') 确实查找了派生路径并神奇地做到了。
    【解决方案2】:

    如果您坚持接受*args,处理这种情况的一种方法如果获得instanceMyForm 很重要,则将instance 作为关键字参数显式包含到@987654325 @,将实例添加到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)
    

    请注意,如果有人将 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)

    【讨论】:

    • 所以也许取消所有位置参数并强制 kwargs 以防止它以无意的方式被使用会更好。只需要让文档字符串拼出真正的论点。不是可以想象到的最佳解决方案,但它可能是我唯一能设计的解决方案。
    • 我认为您可以在 Python 中的“我们都是同意的成年人”概念下提交此文件。此外,如果您是 BaseModelForm 的子类并且它有一个 self.instance 变量,您可以通过 super 直接访问它。例如。 self.instance = super(EdocForm, self).instance。这样,您就可以让超类处理它需要对实例执行的任何操作,并在后处理中为自己获取实例。
    • 不知道为什么我没有想到这一点。哇!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 2016-08-22
    • 2012-05-02
    相关资源
    最近更新 更多