将所有参数和值传递给函数

Kri*_*ass 46 python

我有一个Python函数,fetch_data它可以访问远程API,获取一些数据,然后将它包装在响应对象中.看起来有点像下面这样:

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

现在,响应数据可能会显示"我有更多数据,请使用递增page参数调用我以获得更多".因此,我基本上喜欢在响应对象中存储"方法调用"(函数,参数),因此我可以Response.get_more()查看存储的函数和参数,并再次调用函数(几乎)参数,返回一个新的Response

现在,如果fetch_data被定义为fetch_data(*args, **kwargs)我可能只是存储(fetch_data, args, kwargs)response.不过我有self,foo,barbaz担心-我可以只存储(fetch_data, foo, bar, baz, kwargs)但这是重复的非常不理想的量.

从本质上讲,我试图找出如何,在一个函数中,得到一个完全填充*args**kwargs,其中包括函数的命名参数.

kuz*_*roo 68

从本质上讲,我试图找出如何在函数内获得一个完全填充的*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')
Run Code Online (Sandbox Code Playgroud)

它给出了这个输出:

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'}}
Run Code Online (Sandbox Code Playgroud)

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

  • 在 Python 3.6.9 上为我工作 (3认同)
  • 这是一个很好的答案。但请注意,如果您在类方法内工作,则需要“pop”“self”参数。(除非你需要) (2认同)

Mar*_*ers 27

不是我要做的事,但你可以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)
Run Code Online (Sandbox Code Playgroud)

然后可以将其组合locals()以重建您的参数:

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

但是,在进行高级功能装饰等时,你真的只需要这样的魔力.我觉得这里太过分了.


NPE*_*NPE 13

我认为更浪漫的方法是将您的函数转换为生成器,yield只要服务器不断返回内容就可以获取和获取数据.

这应该会产生整洁的代码,并使您能够跨越迭代保留参数的所有复杂性(Python会神奇地为您做到:-))

  • 这绝对是更适合此类应用的案例之一.这种方式也让OP有机会添加`get_more`方法,返回下一系列生成器迭代的结果. (2认同)

JDG*_*JDG 11

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

>>> def foo(bar, toto):
...     print(locals())
...
>>> foo(3,'sometext')
{'toto': 'sometext', 'bar': 3}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 7

我相信选择的方法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}
Run Code Online (Sandbox Code Playgroud)

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


Vit*_*ich 6

import inspect

def f(x, y):
    print(
        inspect.getargvalues(inspect.currentframe())
    )

f(1, 2)
Run Code Online (Sandbox Code Playgroud)

结果:
ArgInfo(args=['x', 'y'], varargs=None, keywords=None, locals={'y': 2, 'x': 1})

  • 根据文档:“注意此函数在 Python 3.5 中无意中被标记为已弃用。” 文档:https://docs.python.org/3/library/inspect.html (2认同)

Ger*_*ich 5

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'>
Run Code Online (Sandbox Code Playgroud)