【问题标题】:Can you list the keyword arguments a function receives?你能列出函数接收的关键字参数吗?
【发布时间】:2010-09-16 20:28:24
【问题描述】:

我有一个字典,我需要将键/值作为关键字参数传递..例如..

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)

这很好用,但是如果 d_args dict 中有 example 函数不接受的值,它显然会死掉。假设示例函数定义为 @987654323 @

这是一个问题,因为我无法控制 d_argsexample 函数的生成。它们都来自外部模块,example 只接受来自字典..

理想情况下我会这样做

parsed_kwargs = feedparser.parse(the_url)
valid_kwargs = get_valid_kwargs(parsed_kwargs, valid_for = PyRSS2Gen.RSS2)
PyRSS2Gen.RSS2(**valid_kwargs)

我可能会从有效的关键字参数列表中过滤字典,但我想知道:有没有办法以编程方式列出特定函数采用的关键字参数? p>

【问题讨论】:

    标签: python arguments introspection


    【解决方案1】:

    比直接检查代码对象并计算变量更好一点的是使用检查模块。

    >>> import inspect
    >>> def func(a,b,c=42, *args, **kwargs): pass
    >>> inspect.getargspec(func)
    (['a', 'b', 'c'], 'args', 'kwargs', (42,))
    

    如果你想知道它是否可以用一组特定的参数调用,你需要没有指定默认值的参数。这些可以通过:

    def getRequiredArgs(func):
        args, varargs, varkw, defaults = inspect.getargspec(func)
        if defaults:
            args = args[:-len(defaults)]
        return args   # *args and **kwargs are not required, so ignore them.
    

    然后一个函数来告诉你从你的特定字典中缺少什么是:

    def missingArgs(func, argdict):
        return set(getRequiredArgs(func)).difference(argdict)
    

    同样,要检查无效参数,请使用:

    def invalidArgs(func, argdict):
        args, varargs, varkw, defaults = inspect.getargspec(func)
        if varkw: return set()  # All accepted
        return set(argdict) - set(args)
    

    如果它是可调用的,那么一个完整的测试是:

    def isCallableWithArgs(func, argdict):
        return not missingArgs(func, argdict) and not invalidArgs(func, argdict)
    

    (这仅在 python 的 arg 解析方面是好的。显然无法检测到任何运行时检查 kwargs 中的无效值。)

    【讨论】:

    • 不错!我不知道这个功能!
    • 鉴于使用代码对象的方法或多或少是相同的,是否必须再导入一个模块...?
    • @jmets - 绝对 - 使用库模块几乎总是比使用自己的模块更好。此外,代码对象上的属性更加内部,并且可以更改(例如,请注意,这已移至 pyhon3 中的 code)。使用模块作为接口可以让您在某些内部结构发生变化的情况下更加适应未来。它还会做一些你可能没想到的事情,比如在你无法检查的函数(例如 C 函数)上抛出一个适当的类型错误。
    • inspect.getargspec(f) 自 Python 3.0 起已弃用;现代方法是inspect.signature(f)
    • 仅供参考,如果您想支持 Cython 和 Python,此方法不适用于 Cython 的函数。另一方面,co_varnames 选项确实适用于两者。
    【解决方案2】:

    这将打印所有可传递参数的名称,关键字和非关键字:

    def func(one, two="value"):
        y = one, two
        return y
    print func.func_code.co_varnames[:func.func_code.co_argcount]
    

    这是因为第一个 co_varnames 始终是参数(接下来是局部变量,如上例中的 y)。

    所以现在你可以有一个函数:

    def getValidArgs(func, argsDict):
        '''Return dictionary without invalid function arguments.'''
        validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
        return dict((key, value) for key, value in argsDict.iteritems() 
                    if key in validArgs)
    

    然后你可以像这样使用它:

    >>> func(**getValidArgs(func, args))
    

    编辑:一个小补充:如果您真的只需要函数的关键字参数,您可以使用func_defaults 属性来提取它们:

    def getValidKwargs(func, argsDict):
        validArgs = func.func_code.co_varnames[:func.func_code.co_argcount]
        kwargsLen = len(func.func_defaults) # number of keyword arguments
        validKwargs = validArgs[-kwargsLen:] # because kwargs are last
        return dict((key, value) for key, value in argsDict.iteritems() 
                    if key in validKwargs)
    

    您现在可以使用已知 args 调用您的函数,但提取 kwargs,例如:

    func(param1, param2, **getValidKwargs(func, kwargsDict))
    

    这假设func 在其签名中没有使用*args**kwargs 魔法。

    【讨论】:

    • 如果我只想打印出“keyword”参数“keys”怎么办?
    【解决方案3】:

    对于 Python 3 解决方案,您可以使用 inspect.signature 并根据您想了解的 the kind of parameters 进行过滤。

    以位置或关键字、仅关键字、var 位置和 var 关键字参数为例:

    def spam(a, b=1, *args, c=2, **kwargs):
        print(a, b, args, c, kwargs)
    

    你可以为它创建一个签名对象:

    from inspect import signature
    sig =  signature(spam)
    

    然后使用列表推导进行过滤以找出您需要的详细信息:

    >>> # positional or keyword
    >>> [p.name for p in sig.parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD]
    ['a', 'b']
    >>> # keyword only
    >>> [p.name for p in sig.parameters.values() if p.kind == p.KEYWORD_ONLY]
    ['c']
    

    同样,对于使用p.VAR_POSITIONAL 的var 位置和带有VAR_KEYWORD 的var 关键字。

    此外,您可以在 if 中添加一个子句,通过检查 p.default 是否等于 p.empty 来检查是否存在默认值。

    【讨论】:

    • kind 属性非常好用,谢谢!
    【解决方案4】:

    在 Python 3.0 中:

    >>> import inspect
    >>> import fileinput
    >>> print(inspect.getfullargspec(fileinput.input))
    FullArgSpec(args=['files', 'inplace', 'backup', 'bufsize', 'mode', 'openhook'],
    varargs=None, varkw=None, defaults=(None, 0, '', 0, 'r', None), kwonlyargs=[], 
    kwdefaults=None, annotations={})
    

    【讨论】:

      【解决方案5】:

      扩展 DzinX 的答案:

      argnames = example.func_code.co_varnames[:func.func_code.co_argcount]
      args = dict((key, val) for key,val in d_args.iteritems() if key in argnames)
      example(**args)
      

      【讨论】:

        【解决方案6】:

        只需将其用作函数名称“myfun”:

        myfun.__code__.co_varnames
        

        【讨论】:

          猜你喜欢
          • 2014-03-28
          • 1970-01-01
          • 1970-01-01
          • 2017-10-25
          • 1970-01-01
          • 2019-02-15
          • 1970-01-01
          • 1970-01-01
          • 2011-08-28
          相关资源
          最近更新 更多