Python中的实例方法装饰器

3 投票
2 回答
3074 浏览
提问于 2025-04-15 15:38

我想做的事情大概是这样的。我有一个对象的列表,我知道这些对象里面有一个实例方法,长得像这样:

def render(self, name, value, attrs)
   # Renders a widget...

我想在运行时,也就是在遍历这个对象列表的时候,给这些函数加点装饰。这样它们的渲染函数就变成这样:

def render(self, name, value, attrs)
   self.attrs=attrs
   # Renders a widget...

有两个注意事项:

  1. 这个渲染函数是django框架的一部分。我不能在他们的库里面加装饰器(其实可以,但那样我就得自己维护和迁移这个改动)。
  2. 这是一个实例方法。

这里有个例子:

http://wiki.python.org/moin/PythonDecoratorLibrary

这个链接展示了如何给一个类添加新的实例方法。我的不同之处在于,我想在记住那个attrs参数之后,继续调用原来的方法。

2 个回答

3

传统的做法是通过子类来实现。这种方式可以避免去修改别人写的类。

class someclass(object):
    def render(self, name, value, attrs):
        print hasattr(self, 'attrs')

class my_render(object):
    def render(self, name, value, attrs):
        self.attrs = attrs # kind of decorating the function here
        return super(my_render, self).render(name, value, attrs)

class my_class(my_render, someclass): 
    pass    

someclass().render(1,2,3) # -> False
my_class().render(1,2,3) # -> True

使用多重继承的原因是所有的类都可以从 my_render 这个类继承。我个人很喜欢这种混合的概念;-)

class my_otherclass(my_render, someotherclass): pass
class my_thirdclass(my_render, thirdclass): pass

# or less explicit
classlist = [ someclass, someotherclass ]
newclasses = [ type('my_'+cls.__name__, (my_render,cls), {}) for cls in classlist ]
7
def decorate_method(f):
  def wrapper(self, name, value, attrs):
    self.attrs = attrs
    return f(self, name, value, attrs)
  return wrapper

def decorate_class(c):
  for n in dir(c):
    f = getattr(c, n)
    if hasattr(f, 'im_func'):
      setattr(c, n, decorate_method(f.im_func))

你可能还需要一些其他的测试来跳过那些参数不同的方法,不过除此之外,decorate_class(whatever) 应该可以在任何你给定的类 whatever 上实现你想要的功能。

撰写回答