在装饰器中命名的关键字?

时间:2010-06-13 14:36:28

标签: python decorator keyword named-parameters

在我查看其他人的代码之前,我一直在尝试编写自己版本的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

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

3 个答案:

答案 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 ...