Python 能否列出函数接收的关键字参数?

Python 能否列出函数接收的关键字参数?,python,arguments,introspection,Python,Arguments,Introspection,我有一个dict,我需要将键/值作为关键字参数传递。。例如 d_args = {'kw1': 'value1', 'kw2': 'value2'} example(**d_args) 这可以正常工作,但是如果d_args dict中的值不被example函数接受,那么它显然会死掉。。例如,如果示例函数定义为def example(kw2): 这是一个问题,因为我既不控制d_args的生成,也不控制example函数的生成。。它们都来自外部模块,example只接受dict中的一些关键字参数 理

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

d_args = {'kw1': 'value1', 'kw2': 'value2'}
example(**d_args)
这可以正常工作,但是如果d_args dict中的值不被
example
函数接受,那么它显然会死掉。。例如,如果示例函数定义为
def example(kw2):

这是一个问题,因为我既不控制
d_args
的生成,也不控制
example
函数的生成。。它们都来自外部模块,
example
只接受dict中的一些关键字参数

理想情况下,我会这样做

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

我可能只是从有效的关键字参数列表中筛选dict,但我想知道:有没有办法通过编程列出特定函数所使用的关键字参数?

这将打印所有可通过的参数、关键字参数和非关键字参数的名称:

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))

编辑:一个小的添加:如果确实只需要函数的关键字参数,则可以使用
函数默认值
属性来提取它们:

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)
现在,您可以使用已知的参数调用函数,但要提取KWARG,例如:

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

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

扩展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)

使用inspect模块比直接检查代码对象并计算变量要好一点

>>> 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.
然后,一个告诉您的特定dict缺少什么的函数是:

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中的无效值都显然无法检测到。)

在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={})

对于Python3解决方案,可以根据您想了解的内容使用和筛选

使用位置或关键字、仅关键字、变量位置和变量关键字参数获取示例函数:

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\u POSITIONAL
的var位置和使用
var\u关键字的var关键字


此外,您可以向if添加一个子句,通过检查if
p.default
equals
p.empty

来检查是否存在默认值,只需将其用于函数名“myfun”:

myfun.__code__.co_varnames

美好的我不知道这个函数!考虑到使用代码对象的方法或多或少是相同的,那么必须再导入一个模块是否有好处…?@jmets-肯定-实际上使用库模块总比使用自己的模块好。此外,code对象上的属性更为内部,需要更改(例如,请注意,这已移至pyhon3中的代码)。使用该模块作为接口,将来可以为您提供更多的保护,以防这些内部组件发生变化。它还可以做一些您可能没有想到要做的事情,比如在无法检查的函数(例如C函数)上抛出适当的类型错误。
inspect.getargspec(f)
自Python 3.0以来就被弃用了;现代的方法是
inspect.signature(f)
.FYI,如果您想支持Cython和Python,此方法不适用于Cython函数。另一方面,
co_varnames
选项在这两种情况下都可以使用。如果我只想打印“关键字”参数“关键字”,该怎么办?
kind
属性非常方便,谢谢!