我有一个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
中。但是我要担心self
,foo
,bar
和baz
- 我可以存储(fetch_data, foo, bar, baz, kwargs)
,但这是一个非常不受欢迎的重复次数。
基本上,我正在努力研究如何在函数内获得一个完全填充的*args
和**kwargs
,包括函数的命名参数。
答案 0 :(得分:57)
基本上,我正在尝试从函数中找到一个完全填充的* 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'}}
答案 1 :(得分:23)
不是我要做的事情,但您可以使用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]
然而,在进行高级功能装饰等时,你真的只需要这样的魔力。我认为这样做太过分了。
答案 2 :(得分:10)
我认为更加Pythonic的方法是将您的函数转换为生成器,只要服务器不断返回内容,就可以获取和yield
数据。
这应该会产生整洁的代码,并使您能够跨越迭代保留参数的所有复杂性(Python会神奇地为您做到这一点: - )
答案 3 :(得分:5)
我不确定这是你想要的,但是locals()
提供了一个局部变量字典。
>>> def foo(bar, toto):
... print(locals())
...
>>> foo(3,'sometext')
{'toto': 'sometext', 'bar': 3}
答案 4 :(得分:4)
inspect.getargspec
已弃用。使用signature()
和签名对象,它们为callables提供了更好的内省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'>
答案 5 :(得分:1)
import inspect
def f(x, y):
print(
inspect.getargvalues(inspect.currentframe())
)
f(1, 2)
结果:
ArgInfo(args=['x', 'y'], varargs=None, keywords=None, locals={'y': 2, 'x': 1})
请注意,inspect.getargvalues()
已弃用。
答案 6 :(得分:1)
我认为选择的方法是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}
答案 7 :(得分:0)
kwargs不会将'foo','bar'或'bad'作为键,因此您可以将这些条目(带有值)添加到kwargs并只存储(fetch_data,kwargs)。