获取所有参数和值传递给函数


75

我有一个Python函数,fetch_data它可以访问远程API,获取一些数据并将其包装在响应对象中返回。看起来有点像下面的样子:

def fetch_data(self, foo, bar, baz, **kwargs):
    response = Response()
    # Do various things, get some data
    return response

现在,响应数据可能会显示“我有更多数据,请使用递增page参数给我打电话以获取更多”。因此,我本质上想将“方法调用”(函数,参数)存储在响应对象中,这样我就可以拥有一个Response.get_more()查看所存储的函数和参数,然后使用(几乎)相同的函数再次调用该函数。参数,返回一个新的Response

现在,如果fetch_data将其定义为fetch_data(*args, **kwargs)可以存储(fetch_data, args, kwargs)在中response。不过我有selffoobar以及baz约担心-我可以只存储(fetch_data, foo, bar, baz, kwargs)但这是重复的非常不理想的量。

本质上,我正在尝试找出如何从函数内部获取完全填充的*args**kwargs,包括函数的命名参数。


为什么不将foo,bar,baz和kwargs传递给Response()构造函数,以便以后对response.get_more()的调用已经具有这些值?
kurosch 2012年

因为这不能解决问题-Response如果更改的签名,我仍然需要触摸fetch_data
克里斯蒂安·格拉斯

Answers:


99

本质上,我正在尝试找出如何从函数内部获取完全填充的* args和** kwargs,包括函数的命名参数。

如何locals()在函数开始处保存参数?

def my_func(a, *args, **kwargs):
    saved_args = locals()
    print("saved_args is", saved_args)
    local_var = 10
    print("saved_args is", saved_args)
    print("But locals() is now", locals())

my_func(20, 30, 40, 50, kwarg1='spam', kwarg2='eggs')

它给出以下输出:

saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}
saved_args is {'a': 20, 'args': (30, 40, 50), 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}
But locals is now {'a': 20, 'saved_args': {...}, 'args': (30, 40, 50), 'local_var': 10, 'kwargs': {'kwarg1': u'spam', 'kwarg2': u'eggs'}}

帽子提示:https : //stackoverflow.com/a/3137022/2829764


从Python 3.5开始,此功能不适用于默认参数,至少在它们为None时无效。当然,这是另一种情况,不使用* args,** kwargs。
dasWesen

3
适用于我的Python 3.6.9
Addison Klinke '20

31

不是我愿意做的,但是您可以inspect.getargspec用来反省您的方法采用的参数:

>>> import inspect
>>> def foobar(foo, bar, baz):
...     return inspect.getargspec(foobar)
... 
>>> foobar(1, 2, 3)
ArgSpec(args=['foo', 'bar', 'baz'], varargs=None, keywords=None, defaults=None)

然后可以结合使用locals()以重建您的参数:

>>> def foobar(foo, bar, baz):
...     return [locals()[arg] for arg in inspect.getargspec(foobar).args]
... 
>>> foobar(1, 2, 3)
[1, 2, 3]

但是,在执行高级功能装饰器之类时,您实际上仅需要这种魔术。我认为这太过分了。


18

我不确定这正是您想要的,但是locals()提供了局部变量字典。

>>> def foo(bar, toto):
...     print(locals())
...
>>> foo(3,'sometext')
{'toto': 'sometext', 'bar': 3}

14

我认为,更Python化的方式是将您的函数转换为生成器,然后 yield只要服务器不断返回内容读取数据。

这应该产生简洁的代码,并使您能够避免在迭代过程中保留参数的所有复杂性(Python会为您神奇地做到这一点:-))


2
这绝对是更适合此类应用程序的情况之一。这样,OP也有机会添加get_more下一个生成器迭代系列的方法返回结果。
塔德克

问题是,在很多情况下,您都不在乎有更多的数据,因此返回生成器会感觉有些不自然。在返回的对象上带有next()/get_more()的感觉更合适……
Kristian Glass

@KristianGlass:我不确定我是否遵循。您可以轻松地next()在生成器上调用(或不调用)。stackoverflow.com/questions/4741243/...
NPE

是的,但是它将包装响应对象。生成器本质上是包装器,我基本上想要某种生成器y mixin
Kristian Glass

9

inspect.getargspec从3.0版开始不推荐使用。使用signature()和签名对象,为可调用对象提供更好的自省API。

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass

>>> sig = signature(foo)

>>> str(sig)
'(a, *, b:int, **kwargs)'

>>> str(sig.parameters['b'])
'b:int'

>>> sig.parameters['b'].annotation
<class 'int'>


4

我相信选择方法是getcallargs从中选择的,inspect因为它返回将调用函数的实参。您将一个函数以及args和kwargs传递给该函数(inspect.getcallargs(func, /, *args, **kwds)),它将返回用于调用的真实方法的参数,同时考虑默认值和其他内容。请看下面的例子。

from inspect import getcallargs

# we have a function with such signature
def show_params(first, second, third=3):
    pass

# if you wanted to invoke it with such params (you could get them from a decorator as example)
args = [1, 2, 5]
kwargs = {}
print(getcallargs(show_params, *args, **kwargs))
#{'first': 1, 'second': 2, 'third': 5}

# here we didn't specify value for d
args = [1, 2, 3, 4]
kwargs = {}

# ----------------------------------------------------------
# but d has default value =7
def show_params1(first, *second, d = 7):
    pass


print(getcallargs(show_params1, *args, **kwargs))
# it will consider b to be equal to default value 7 as it is in real method invocation
# {'first': 1, 'second': (2, 3, 4), 'd': 7}

# ----------------------------------------------------------
args = [1]
kwargs = {"d": 4}

def show_params2(first, d=3):
    pass


print(getcallargs(show_params2, *args, **kwargs))
#{'first': 1, 'd': 4}

https://docs.python.org/3/library/inspect.html


1

kwargs不会将'foo','bar'或'bad'作为键,因此您可以将这些条目(带有其值)添加到kwargs中,而仅存储(fetch_data,kwargs)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.