2010-06-13 58 views
0

我一直在深入玩弄,试图在我去看别人的代码之前编写我自己版本的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 

为什么我不能使用关键参数以这种方式装饰?我做错了什么,你能告诉我该怎么做吗?

回答

5

您需要定义一个返回装饰功能:

def addValue(val): 
    def decorator(func): 
     def add(x): 
      return func(x) + val 
     return add 
    return decorator 

当你写@addTwoaddTwo值被直接用作装饰。但是,当您编写@addValue(4)时,首先调用addValue函数来计算addValue(4)。然后结果被用作装饰器。

+0

所以你说,在Python装饰者雇用急切的评价?真是无赖。 – wheaties 2010-06-13 15:03:29

5

想要部分应用函数addValue - 给出val参数,但不给出func。通常有两种方法可以做到这一点:

第一个被称为讨好和interjay的回答用:而不是用两个参数,f(a,b) -> res一个功能,你写的第一个参数的函数,返回另一个功能采取第二个参数g(a) -> (h(b) -> res)

另一种方法是functools.partial对象。它使用函数检查来找出函数需要运行的参数(funcval)。您可以在创建局部时添加额外的参数,一旦您调用局部参数,它将使用所有额外的参数。

from functools import partial 
@partial(addValue, val=2) # you can call this addTwo 
def computeSomething(x): 
    return x 

局部模板通常是这种局部应用问题更简单的解决方案,特别是与多个参数。

+0

functools.partial,非常好。我知道有一种简单的方法可以在Python中完成currying,而不需要三重缩进。非常感谢。 – wheaties 2010-06-13 15:17:34

3

装饰与任何种参数 - 名为/关键字的,无名/位置的人,或者一些各自的 - 基本上,那些你通话@name行而不只是有 - 需要一个嵌套级别(而你刚才提到的装饰器只有一个嵌套级别)。这甚至去为了论证少的,如果你想呼叫他们在@线 - 这里是最简单的,什么也不做,双层嵌套的装饰:

def double(): 
    def middling(): 
    def inner(f): 
     return f 
    return inner 
    return middling 

你会使用这个作为

@double() 
def whatever ... 

注意括号(在这种情况下,空的,因为没有必要论据和希望):他们的意思是你调用double,它返回middling,其装饰whatever

一旦你已经看到了 “呼唤” 和 “只提”,加入(如可选)命名ARGS之间的差异并不难:

def doublet(foo=23): 
    def middling(): 
    def inner(f): 
     return f 
    return inner 
    return middling 

可无论是作为:

@doublet() 
def whatever ... 

或为:

@doublet(foo=45) 
def whatever ... 

或等效为:

@doublet(45) 
def whatever ...