装饰类方法的pythonic方式

pythonic way of decorating classmethods

给定以下示例:

class A:
    def f(self, x):
        return 2*x 

我想写另一个方法,它使用上面的 f 但添加一个常量,即

class A:
        def f(self, x):
            return 2*x
        def g(self, x):
            return self.f(x) + 10

这是一种方式。然而,这闻起来很像装修!执行此操作的正确 pythonic 方法是什么?

你可以在class外写一个简单的函数:

def add_val(f):
  def wrapper(cls, _x):
    return f(cls, _x) + 10
  return wrapper


class A:
  @add_val
  def f(self, x):
    return 2*x 
print(A().f(20))

输出:

50

编辑:您可以在 Python3 中使用 functools.wrapsclassmethod。包装函数 f 将 return x*2 并且装饰器 g 会将 10 添加到传递给它的函数的 returned 结果。但是,为了能够保存 f 的原始功能,您可以利用 __wrapped__ 属性:

import functools
def g(f):
  @functools.wraps(f)
  def wrapper(cls, _x):
    return f(cls, _x)+10
  return wrapper

class A:
   @classmethod
   @g
   def f(cls, x):
     return x*2

f_1 = functools.partial(A.f.__wrapped__, A)
print(A.f(4))
print(f_1(4))

输出:

18
8

@Ajax1234 的扩展答案,您可以尝试: - 参数化你的装饰器, - 显式调用你的装饰器(没有 @)。

def add_val(_value):
  def decorator(f):
    def wrapper(cls, _x):
      return f(cls, _x) + _value
    return wrapper

  return decorator

class A:
  def f(self, x):
    return 2*x 

  g = add_val(10)(f)

[编辑]

您还可以使用 functools.wraps() 改进装饰器(它本身就是一个装饰器)。您需要做的就是更改包装器声明:

@functools.wraps(f)
def wrapper(cls, _x):
  return f(cls, _x) + _value