如何使用functools.封装并设置一个参数



我试着研究这个问题,但找不到答案——对不起,如果我错过了。基本上,我有以下问题。我有一个功能:

def f(a, b, c, d, e):
...

我还有第二个函数,它调用f,但从a推断出一些参数:

def g(a, **kwargs):
b = deduce(a)
return f(a, b, **kwargs)

现在用functools.wrapsf复制kwargs会很好。但是我不能直接使用,因为f的签名和g的签名不匹配:参数bg中是固定的。我希望有一种方法可以清楚地表明gf的函数,但b是推导出来的。

我希望问题是清楚的;我很想听听你的想法!

我认为在这种情况下,只要有一个明确的文档字符串将是所有你需要的。functools.wraps对于要完全取代原始定义的装饰器更有用。对于一个单独的函数(gf仍独立引用)你不应该使用。

您还需要处理用户没有提供关键字args的情况。例如,下面的代码将会失败:

>>> f(1,2,3,4,5)
>>> g(1,3,4,5)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: g() takes 1 positional argument but 4 were given

g工作,你需要做:

def g(a, *args, **kwargs):
b = deduce(a)
return f(a, b, *args, **kwargs)

另外,如果您担心f的签名在g下面发生变化,那么您还应该防止开始参数的顺序发生变化。

为了使f在更改签名时尽可能好用,可能值得完全禁止使用位置参数。(还添加了漂亮的文档字符串):

def f(*, a, b, c, d, e):
...

def g(*, a, **kwargs):
"""
Acts in the same way as function `f`, however, argument `b` must
be omitted as it will be deduced from `a`.
"""
return f(**kwargs, a=a, b=deduce(a))

这也保持了一个很好的副作用,即禁止您在显式定义b时调用g:

>>> g(a=1, b=2, c=3, d=4, e=0)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 14, in g
TypeError: __main__.f() got multiple values for keyword argument 'b'

my .

如果这是一个将被许多人使用的库,那么如果在签名中显式列出值会更好。这将允许静态分析工具在运行前捕获错误。

当您有很多参数时,这很容易出错,但是使用pyi存根文件时,您只需要这样做一次(而不是实际执行的代码)。实际代码中的样板保持最小,并且预期的定义对用户来说变得清晰。

g.py

def g(*, a, **kwargs):
"""
Acts in the same way as function `f`, however, argument `b` must
be omitted as it will be deduced from `a`.
"""
return f(**kwargs, a=a, b=deduce(a))

g.pyi

def g(*, a, c, d, e): ...

最新更新