获取函数参数的默认值?

2025-02-27 09:06:00
admin
原创
62
摘要:问题描述:对于此功能def eat_dog(name, should_digest=True): print "ate dog named %s. Digested, too? %" % (name, str(should_digest)) 我想在函数外部读取其参数和任何附加的默认...

问题描述:

对于此功能

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

我想在函数外部读取其参数和任何附加的默认值。因此,对于这个特定示例,我想知道name没有默认值(即它是一个必需参数),并且这True是的默认值should_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 公开模块中的函数。如果调用者省略了某些函数参数,我希望返回一个特定错误,该错误会指明省略的特定函数参数。如果客户端省略了参数,但函数签名中提供了默认值,我希望使用该默认值。


解决方案 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(旧答案)

args/defaults 可以组合为:

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

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

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


查看文档,此解决方案仅适用于 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)))

也会起作用,并且对某些人来说可能更直观。


解决方案 2:

根据您的确切需要,您可能不需要该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 

解决方案 3:

对于那些寻找一个版本来通过mgilson 的答案获取特定默认参数的人来说。

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

解决方案 4:

您可以使用inspect模块及其getargspec功能:

inspect.getargspec(func)

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

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

解决方案 5:

TLDR;

您可以通过其他帖子中提到的一些__dunder__变量获得此值而无需任何导入。将其放入一个简单的辅助函数中可以得到一个默认值字典。

def get_defaults(fn):
    """
    Get the default values of the passed function or method.
    """
    output = {}
    if fn.__defaults__ is not None:
        # Get the names of all provided default values for args
        default_varnames = list(fn.__code__.co_varnames)[:fn.__code__.co_argcount][-len(fn.__defaults__):]
        # Update the output dictionary with the default values
        output.update(dict(zip(default_varnames, fn.__defaults__)))
    if fn.__kwdefaults__ is not None:
        # Update the output dictionary with the keyword default values
        output.update(fn.__kwdefaults__)
    return output

利用以下 dunder 变量:

  • .__code__.co_varnames:所有输入变量名称的元组

  • .__code__.co_argcount:函数中参数(非关键字)的数量

  • .__defaults__:默认值的元组

  • .__kwdefaults__:关键字默认值的字典

编辑 1 - 感谢@griloHBG - 添加了 if 语句以防止在未指定默认值时出现异常。

编辑 2 - 修改以使其更通用(支持函数和方法的默认值和 kwdefaults)

测试

功能测试

# Tests
def test_fn(a, b, c=3, d=4, *args, **kwargs):
    pass

def test_fn_2(a, b, c=1, *args, d, e=2, **kwargs):
    pass

print(get_defaults(test_fn)) #=> {'c': 3, 'd': 4}
print(get_defaults(test_fn_2)) #=> {'c': 1, 'e': 2}

类测试(方法 / 类方法 / 静态方法)

# Class Tests
class Test:
    def __init__(self, a, b, c=3, d=4, *args, **kwargs):
        pass

    def test_fn_2(self, a, b, c=1, *args, d, e=2, **kwargs):
        pass

    @staticmethod
    def test_fn_3(a, b, c=1, *args, d, e=2, **kwargs):
        pass

    @classmethod
    def test_fn_4(cls, a, b, c=1, *args, d, e=2, **kwargs):
        pass

# Uninitialized Class Tests
print(get_defaults(Test.__init__)) #=> {'c': 3, 'd': 4}
print(get_defaults(Test.test_fn_2)) #=> {'c': 1, 'e': 2}
print(get_defaults(Test.test_fn_3)) #=> {'c': 1, 'e': 2}
print(get_defaults(Test.test_fn_4)) #=> {'c': 1, 'e': 2}
# Initialized Class Tests
test_object = Test(1, 2)
print(get_defaults(test_object.__init__)) #=> {'c': 3, 'd': 4}
print(get_defaults(test_object.test_fn_2)) #=> {'c': 1, 'e': 2}
print(get_defaults(Test.test_fn_3)) #=> {'c': 1, 'e': 2}
print(get_defaults(Test.test_fn_4)) #=> {'c': 1, 'e': 2}

解决方案 6:

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

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

解决方案 7:

在 Python 中,所有具有默认值的参数都位于没有默认值的参数之后。因此映射应从末尾开始,直到用尽默认值列表。因此逻辑如下:

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

给出正确映射的默认值。

解决方案 8:

对@conmak 的答案进行简单修改,None当函数具有命名参数但没有默认值时,仍然返回带有值的字典:

def my_fn(a, b=2, c='a'):
    pass

def get_defaults(fn):
    ### No arguments
    if isinstance(fn.__code__.co_varnames, type(None)):
        return {}
    ### no defaults
    if isinstance(fn.__defaults__, type(None)):
        return dict(zip(
            fn.__code__.co_varnames, 
            [None]*(fn.__code__.co_argcount)
        ))
    ### every other case
    return dict(zip(
        fn.__code__.co_varnames, 
        [None]*(fn.__code__.co_argcount - len(fn.__defaults__)) + list(fn.__defaults__)
    ))

print(get_defaults(my_fn))

现在应该给出:

{'a': None, 'b': 2, 'c': 'a'}
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3892  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2717  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   52  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   54  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   49  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用