【问题标题】:Get a function argument's default value?获取函数参数的默认值?
【发布时间】:2012-09-27 17:40:07
【问题描述】:

对于这个功能

def eat_dog(name, should_digest=True):
    print "ate dog named %s. Digested, too? %" % (name, str(should_digest))

我想在函数外部读取它的参数和任何附加的默认值。所以对于这个具体的例子,我想知道name 没有默认值(即它是一个必需的参数)并且Trueshould_digest 的默认值。

我知道inspect.getargspec(),它确实为我提供了有关参数和默认值的信息,但我发现两者之间没有任何联系:

ArgSpec(args=['name', 'should_digest'], varargs=None, keywords=None, defaults=(True,))

从这个输出我怎么知道True(在defaults元组中)是should_digest的默认值?

此外,我知道解决问题的“请求宽恕”模型,但不幸的是,该错误的输出不会告诉我缺少的参数的名称:

>>> eat_dog()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: eat_dog() takes at least 1 argument (0 given)

为了提供上下文(我为什么要这样做),我通过 JSON API 公开模块中的函数。如果调用者省略了某些函数参数,我想返回一个特定的错误来命名被省略的特定函数参数。如果客户端省略了参数,但函数签名中提供了默认值,我想使用该默认值。

【问题讨论】:

    标签: python


    【解决方案1】:

    Python3.x

    在 python3.x 世界中,您可能应该使用 Signature 对象:

    import inspect
    
    def get_default_args(func):
        signature = inspect.signature(func)
        return {
            k: v.default
            for k, v in signature.parameters.items()
            if v.default is not inspect.Parameter.empty
        }
    

    Python2.x(旧答案)

    参数/默认值可以组合为:

    import inspect
    a = inspect.getargspec(eat_dog)
    zip(a.args[-len(a.defaults):],a.defaults)
    

    这里a.args[-len(a.defaults):] 是具有默认值的参数,显然a.defaults 是相应的默认值。

    您甚至可以将zip 的输出传递给dict 构造函数,并创建一个适合关键字解包的映射。


    查看文档,此解决方案仅适用于 python2.6 或更高版本,因为我假设 inspect.getargspec 返回一个命名元组。早期版本返回一个正则元组,但它会很容易进行相应的修改。这是一个适用于旧(和新)版本的版本:

    import inspect
    def get_default_args(func):
        """
        returns a dictionary of arg_name:default_values for the input function
        """
        args, varargs, keywords, defaults = inspect.getargspec(func)
        return dict(zip(args[-len(defaults):], defaults))
    

    想一想:

        return dict(zip(reversed(args), reversed(defaults)))
    

    也可以,而且对某些人来说可能更直观。


    【讨论】:

    • @Tadeck -- 我必须支持你的。我只是在猜测如何将它们结合起来,直到我看到你的帖子证实了我的怀疑。
    • @Tadeck 你能解释一下这是如何工作的吗?我对发生的事情有点困惑。
    • @skyler -- 你知道zip 函数吗?哪部分不明白。如果你能告诉我什么让你感到困惑,我会很乐意改进答案。
    • @mgilson 我想我现在明白了。具有默认值的 args 不能与没有默认值的 args 穿插,因此将默认值映射到 args 列表,从最后一个参数开始并向后移动,正确连接两者。
    • @skyler -- 没错。我自己说得再好不过了。
    【解决方案2】:

    您可以将inspect 模块与它的getargspec function 一起使用:

    inspect.getargspec(func)

    获取 Python 函数参数的名称和默认值。返回四个事物的tuple(args, varargs, keywords, defaults)args 是参数名称列表(它可能包含嵌套列表)。 varargskeywords*** 参数或 None 的名称。 defaults 是默认参数值的元组None(如果没有默认参数);如果这个元组有n 元素,它们对应于args 中列出的最后一个n 元素。

    有关如何检索参数名称及其默认值的确切代码,请参阅 mgilson's answer

    【讨论】:

      【解决方案3】:

      根据您的具体需要,您可能不需要inspect 模块,因为您可以检查函数的__defaults__ 属性:

      >>> eat_dog.__defaults__
      (True,)
      >>> eat_dog.__code__.co_argcount
      2
      >>> eat_dog.__code__.co_varnames
      ('name', 'should_digest')
      >>> 
      >>> eat_dog.__kwdefaults__
      >>> eat_dog.__code__.co_kwonlyargcount
      0 
      

      【讨论】:

        【解决方案4】:

        对于那些正在寻找使用mgilson's 答案获取特定默认参数的版本的人。

            value = signature(my_func).parameters['param_name'].default
        

        这是一个完整的工作版本,在Python 3.8.2完成

        from inspect import signature
        
        def my_func(a, b, c, param_name='apple'):
            pass
        
        value = signature(my_func).parameters['param_name'].default
        
        print(value == 'apple') # True
        
        

        【讨论】:

          【解决方案5】:

          处理仅关键字参数(并且因为默认值和 kwonlydefaults 可以是 None):

          spec = inspect.getfullargspec(func)
          defaults = dict(zip(spec.args[::-1], (spec.defaults or ())[::-1]))
          defaults.update(spec.kwonlydefaults or {})
          

          【讨论】:

          • 是的。 +1 指出这一点。我最初的答案是在 python3.x 流行之前写的。事实证明,现在甚至还有一种 更好的 方法可以使用 Signature 对象(我已将其添加到我的原始答案中)来处理这个问题
          【解决方案6】:

          在python中,所有有默认值的参数都在没有默认值的参数之后。所以映射应该从头开始,直到你用完默认值列表。因此逻辑:

          dict(zip(reversed(args), reversed(defaults)))
          

          给出正确映射的默认值。

          【讨论】:

            猜你喜欢
            • 2016-01-01
            • 2011-02-20
            • 2011-04-09
            • 1970-01-01
            • 2010-11-28
            • 1970-01-01
            • 1970-01-01
            • 2015-12-10
            相关资源
            最近更新 更多