Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中创建函数参数的签名_Python_Python 3.x_Function_Parameters - Fatal编程技术网

在Python中创建函数参数的签名

在Python中创建函数参数的签名,python,python-3.x,function,parameters,Python,Python 3.x,Function,Parameters,我有一个函数需要很长时间,并且需要能够缓存它自己的结果,以便在使用相同参数再次调用它时使用。请参阅下面的示例,该示例似乎解决了问题。我正在使用Python 3.6 我的问题围绕这一行: param_sig = repr(locals()) 1) 是否有一种更类似python的方法来获得传递给函数的参数的唯一签名 2) 我可以依赖Python将函数参数插入到locals()映射中的顺序吗?同样,这似乎可行,但如果需要,我可以在一个不太优雅的签名创建者中显式地重新列出每个参数,如: param_s

我有一个函数需要很长时间,并且需要能够缓存它自己的结果,以便在使用相同参数再次调用它时使用。请参阅下面的示例,该示例似乎解决了问题。我正在使用Python 3.6

我的问题围绕这一行:

param_sig = repr(locals())
1) 是否有一种更类似python的方法来获得传递给函数的参数的唯一签名

2) 我可以依赖Python将函数参数插入到locals()映射中的顺序吗?同样,这似乎可行,但如果需要,我可以在一个不太优雅的签名创建者中显式地重新列出每个参数,如:

param_sig = "{},{},{}".format(a,b,c)
示例代码:

import random
cached_answers = {}

def f(a=1, b=2, c=3):
    param_sig = repr(locals())
    if param_sig in cached_answers:
        ans = cached_answers[param_sig]
        print("Call: {} = CACHED {}".format(param_sig,ans))
        return ans
    else:
        # do heavy lifting then cache the result
        ans = random.random()
        print("Call: {} = {}".format(param_sig,ans))
        cached_answers[param_sig] = ans
        return ans

# various calls... some of which are repeated and should be cached
f()
f(b=9)
f(c=9, a=9)
f()               # should be cached
parms={'a':9}
f(**parms)
f(b=9)            # should be cached
f(a=9)            # should be cached
repr(locals())
非常糟糕,因为它不适用于此函数。它会起作用,或者可以让它起作用,我可以深入研究一些问题,而不是这样做的语义

我将回到问题上来-首先,您的解决方案:

Python有一个缓存函数,就像您在stdlib上的
functools
模块中需要的一样-只需导入它并将其用作装饰器:

from functools import lru_cache

@lru_cache()
def f(a=1, b=2, c=3):
   # just put the heavy stuff inside your original "else" clause here
现在,我们来理解为什么decorators有一个更好的解决方案:缓存结果的逻辑与函数的逻辑完全不混合,而且,缓存所使用的任何方法都可以用于缓存程序中的任何函数—无需在每个函数体中复制缓存代码

您将了解到,虽然Python自己的
lru\u缓存
与您的情况相匹配,但它并不是最佳匹配,也不是所有情况下的完美匹配-无论如何,您最好安装第三方缓存包或滚动您自己的缓存,但保持逻辑分离

可以应用于系统中各种类似函数或方法的特定编程逻辑的概念称为,而Python decorator语法是一种廉价使用它的好方法


除了将逻辑与函数分离,并使用
repr(locals())
序列化参数之外,您的方法是正确的:为每组参数保留一个(模块)全局字典是缓存函数的常用方法。
lru\u缓存
恰好以一种透明的方式对其进行处理。

通过使用*args(提供位置参数列表)或**kwargs(一种“关键字”参数的dict)语法提供参数,您可以以确定的顺序访问参数。考虑:

>>> def fn(*args):
...     for i in args: print(i)
... 
>>> fn('a', 'b', 'c')
a
b
c

要在缓存中使用这些参数,需要将args转换为dict键。 我建议对缓存键使用元组,而不是将其格式化为字符串。元组是不可变的,因此可以对它们进行散列(dict的一个要求)。例如:

>>> cache=dict()
>>> def fn3(**kwargs):
...     key=(kwargs['a'], kwargs['b'], kwargs['c'])
...     val = ':'.join( (kwargs['a'], kwargs['b'], kwargs['c']) )
...     print(str(key))
...     print(val)
...     cache[key] = val
...     return
... 
>>> fn3(a='1', b='2', c='3')
('1', '2', '3')
1:2:3
>>> print(str(cache))
{('1', '2', '3'): '1:2:3'}

…为什么不用?谢谢,杰夫。这似乎是假设所有参数都没有默认值,并更改了函数代码,因为kwargs参数在函数中不能作为局部变量使用。我喜欢使用元组作为键的想法。谢谢。我的特定问题(获取参数签名)的答案在lru_缓存代码中。正如您所猜测的,我的实际问题比缓存示例要复杂一些,但我没有考虑使用装饰器,这似乎是正确的解决方案。
>>> cache=dict()
>>> def fn3(**kwargs):
...     key=(kwargs['a'], kwargs['b'], kwargs['c'])
...     val = ':'.join( (kwargs['a'], kwargs['b'], kwargs['c']) )
...     print(str(key))
...     print(val)
...     cache[key] = val
...     return
... 
>>> fn3(a='1', b='2', c='3')
('1', '2', '3')
1:2:3
>>> print(str(cache))
{('1', '2', '3'): '1:2:3'}