假设函数a_method的定义如下
def a_method(arg1, arg2):
pass
从a_method本身开始,我怎么能得到参数名-例如,作为字符串的元组,如("arg1", "arg2")?
假设函数a_method的定义如下
def a_method(arg1, arg2):
pass
从a_method本身开始,我怎么能得到参数名-例如,作为字符串的元组,如("arg1", "arg2")?
当前回答
对于那些像我一样正在寻找将所有参数及其值(默认值或非默认值)放入一个字典的解决方案的人,我还有另一个建议。
import inspect
def get_arguments(func, args, kwargs, is_method=False):
offset = 1 if is_method else 0
specs = inspect.getfullargspec(func)
d = {}
for i, parameter in enumerate(specs.args[offset:]):
i += offset
if i < len(args):
d[parameter] = args[i]
elif parameter in kwargs:
d[parameter] = kwargs[parameter]
else:
d[parameter] = specs.defaults[i - len(args)]
return d
现在在这样的装饰器中打印get_arguments的返回值
def a_function_decorator(func):
def inner(*args, **kwargs):
print(get_arguments(func, args, kwargs))
return func(*args, **kwargs)
return inner
把它应用到一个函数上
@a_function_decorator
def foo(a, b, c="default_c", d="default_d"):
pass
会给我们
foo(1, 2, d="eek")
# {'a': 1, 'b': 2, 'c': 'default_c', 'd': 'eek'}
foo(1, 2, "blah")
# {'a': 1, 'b': 2, 'c': 'blah', 'd': 'default_c'}
foo(1, 2)
# {'a': 1, 'b': 2, 'c': 'default_c', 'd': 'default_d'}
方法也是一样
def a_method_decorator(func):
def inner(*args, **kwargs):
print(get_arguments(func, args, kwargs, is_method=True))
return func(*args, **kwargs)
return inner
class Bar:
@a_method_decorator
def foo(self, a, b, c="default_c", d="default_d"):
pass
Bar().foo(1, 2, d="eek")
#{'a': 1, 'b': 2, 'c': 'default_c', 'd': 'eek'}
Bar().foo(1, 2, "blah")
# {'a': 1, 'b': 2, 'c': 'blah', 'd': 'default_c'}
Bar().foo(1, 2)
# {'a': 1, 'b': 2, 'c': 'default_c', 'd': 'default_d'}
它当然不是最漂亮的解决方案,但它是我见过的第一个完全符合我要求的解决方案。
其他回答
现在dir()和vars()呢?
似乎做什么是被要求超级简单…
必须从函数范围内调用。
但要注意,它将返回所有局部变量,所以如果需要,请确保在函数的最开始执行。
还要注意,正如评论中指出的那样,这不允许从作用域之外执行此操作。所以不完全是OP的情况,但仍然符合题目。这就是我的回答。
在CPython中,参数的数量是
a_method.func_code.co_argcount
他们的名字在开头
a_method.func_code.co_varnames
这些是CPython的实现细节,所以这可能不适用于Python的其他实现,比如IronPython和Jython。
承认“传递”参数的一种可移植方法是使用func(*args, **kwargs)签名来定义函数。这在matplotlib中被大量使用,其中外层API层将大量关键字参数传递给底层API。
Python 3.5 +:
DeprecationWarning: inspect.getargspec()自Python 3.0起已弃用,请使用inspect.signature()或inspect.getfullargspec()
所以之前:
func_args = inspect.getargspec(function).args
Now:
func_args = list(inspect.signature(function).parameters.keys())
测试:
'arg' in list(inspect.signature(function).parameters.keys())
假设函数function接受参数arg,它的值为True,否则为False。
来自Python控制台的示例:
Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32
>>> import inspect
>>> 'iterable' in list(inspect.signature(sum).parameters.keys())
True
在Python 3中。+有了Signature对象,获得参数名到值之间映射的简单方法就是使用Signature的bind()方法!
例如,这是一个用于打印地图的装饰器:
import inspect
def decorator(f):
def wrapper(*args, **kwargs):
bound_args = inspect.signature(f).bind(*args, **kwargs)
bound_args.apply_defaults()
print(dict(bound_args.arguments))
return f(*args, **kwargs)
return wrapper
@decorator
def foo(x, y, param_with_default="bars", **kwargs):
pass
foo(1, 2, extra="baz")
# This will print: {'kwargs': {'extra': 'baz'}, 'param_with_default': 'bars', 'y': 2, 'x': 1}
看一下inspect模块——它将为你检查各种代码对象属性。
>>> inspect.getfullargspec(a_method)
(['arg1', 'arg2'], None, None, None)
其他结果是*args和**kwargs变量的名称,以及提供的默认值。ie。
>>> def foo(a, b, c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))
注意,在Python的某些实现中,一些可调用对象可能不是可内省的。例如,在CPython中,一些用C定义的内置函数不提供关于其参数的元数据。因此,如果在内置函数上使用inspect.getfullargspec(),将会得到一个ValueError。
从Python 3.3开始,你可以使用inspect.signature()来查看可调用对象的调用签名:
>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>