在我查看其他人的代码之前,我一直在尝试编写自己版本的memoizing装饰器。老实说,这更像是一种有趣的运动。然而,在玩耍的过程中,我发现我不能用装饰师做我想做的事。
def addValue( func, val ):
def add( x ):
return func( x ) + val
return add
@addValue( val=4 )
def computeSomething( x ):
#function gets defined
如果我想这样做,我必须这样做:
def addTwo( func ):
return addValue( func, 2 )
@addTwo
def computeSomething( x ):
#function gets defined
为什么我不能以这种方式使用装饰器的关键字参数?我做错了什么,你能告诉我我应该怎么做吗?
答案 0 :(得分:5)
您需要定义一个返回装饰器的函数:
def addValue(val):
def decorator(func):
def add(x):
return func(x) + val
return add
return decorator
当您编写@addTwo
时,addTwo
的值将直接用作装饰器。但是,当您编写@addValue(4)
时,首先通过调用addValue函数来评估addValue(4)
。然后将结果用作装饰器。
答案 1 :(得分:5)
您希望部分应用函数addValue
- 提供val
参数,但不是func
。通常有两种方法:
第一个被称为 currying 并在interjay的答案中使用:代替具有两个参数f(a,b) -> res
的函数,你编写了第一个arg的函数,它返回另一个函数第二个arg g(a) -> (h(b) -> res)
另一种方式是functools.partial
对象。它使用函数检查来确定函数需要运行的参数(在您的情况下为 func 和 val )。您可以在创建partial时添加额外的参数,一旦调用partial,它将使用给定的所有额外参数。
from functools import partial
@partial(addValue, val=2 ) # you can call this addTwo
def computeSomething( x ):
return x
对于此部分应用程序问题,部分通常是一个更简单的解决方案,尤其是对于多个参数。
答案 2 :(得分:3)
具有任何种类的参数的装饰者 - 名为/关键字的,未命名的/位置的,或者每个的一些 - 基本上是{strong>调用 {{ 1}}行而不仅仅是提及 - 需要双级别的嵌套(而您刚才提到的装饰器只有一级嵌套)。如果你想在@name
行中调用它们,那么即使对于没有参数的那些也是如此 - 这里是最简单的,无所事事,双嵌套的装饰器:
@
您将其用作
def double():
def middling():
def inner(f):
return f
return inner
return middling
注意括号(在这种情况下为空,因为不需要也不需要参数):它们意味着你调用 @double()
def whatever ...
,它返回double
,它装饰middling
。
一旦你看到“调用”和“只是提及”之间的区别,添加(例如可选)命名args并不难:
whatever
可用作:
def doublet(foo=23):
def middling():
def inner(f):
return f
return inner
return middling
或作为:
@doublet()
def whatever ...
或等同于:
@doublet(foo=45)
def whatever ...