【问题标题】:Named keywords in decorators?装饰器中的命名关键字?
【发布时间】:2011-03-03 05:36:01
【问题描述】:

在查看其他人的代码之前,我一直在尝试编写自己的记忆装饰器版本。老实说,这更像是一种有趣的练习。然而,在玩的过程中,我发现我不能用装饰器做我想做的事情。

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

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

【问题讨论】:

    标签: python decorator keyword named-parameters


    【解决方案1】:

    具有任何种参数的装饰器——命名/关键字参数、未命名/位置参数或每种参数中的一些——本质上,你在@987654321上调用 @ 行而不只是 提及 -- 需要一个 double 级别的嵌套(而您刚刚提到的装饰器具有单级嵌套)。如果您想在@ 行中调用它们,这甚至适用于无参数的装饰器——这是最简单的、无操作的双嵌套装饰器:

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

    你会用这个

    @double()
    def whatever ...
    

    注意括号(在这种情况下为空,因为不需要也不需要参数):它们表示您正在调用double,它返回middling,它装饰whatever

    一旦您了解了“调用”和“仅提及”之间的区别,添加(例如可选的)命名参数并不难:

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

    【讨论】:

      【解决方案2】:

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

      第一个称为 currying 并在 interjay 的回答中使用:而不是具有两个参数的函数 f(a,b) -> res,您编写一个第一个 arg 的函数,该函数返回另一个函数,该函数采用第二个参数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
      

      对于这个部分应用程序问题,Partials 通常是一种更简单的解决方案,尤其是在有多个参数的情况下。

      【讨论】:

      • functools.partial,非常好。我知道有一种简单的方法可以在 Python 中完成柯里化,而无需三次缩进。非常感谢。
      【解决方案3】:

      你需要定义一个返回装饰器的函数:

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

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

      【讨论】:

      • 所以你是说在 Python 装饰器中使用热切评估?真可惜。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      • 2019-06-14
      • 2023-04-06
      • 1970-01-01
      • 2021-03-29
      • 2018-10-25
      • 2021-09-29
      相关资源
      最近更新 更多