2012-09-11 31 views
3

这很难。我不仅要动态地创建方法,而且要将装饰器与它们关联起来。这是我试过用Python中的装饰器创建动态方法

import inspect 
import types 

class Dynamo(object): 
    pass 

def call_me_dec(func): 
    print 'I am here' 
    return func 

def add_dynamo(cls,i): 
    # @call_me_dec 
    def innerdynamo(self): 
     print "in dynamo %d" % i 
     return i 

    innerdynamo.__doc__ = "docstring for dynamo%d" % i 
    innerdynamo.__name__ = "dynamo%d" % i 
    setattr(cls, innerdynamo.__name__, innerdynamo) 

def add_decorators(cls): 
    for name, fn in inspect.getmembers(cls): 
     if isinstance(fn, types.UnboundMethodType): 
      setattr(cls, name, call_me_dec(fn)) 

for i in range(2): 
    add_dynamo(Dynamo, i) 

add_decorators(Dynamo) 

d=Dynamo() 
d.dynamo0() 
d.dynamo1() 

输出是:

I am here 
    I am here 
    in dynamo 0 
    in dynamo 1 

预期输出:

I am here 
    in dynamo 0 
    I am here 
    in dynamo 1 

请解释为什么会出现这种情况,我怎么能得到期望的结果?

回答

5

您已经看到,因为在创建装饰函数时调用装饰器代码,而不是调用函数时调用装饰器代码。如果你想让代码在调用中运行,你需要让装饰器返回一个调用装饰方法的可调用对象(通常是一个闭包)。例如:

def call_me_dec(func): 
    print 'Decorating %s' % func 
    def func_wrapper(*args, **kwargs): 
     print 'Calling %s' % func 
     return func(*args, **kwargs) 
    return func_wrapper 

装饰语法只是语法糖。记住:

def func(): 
    pass 
func = deco(func) 

相当于

@deco 
def func(): 
    pass 

无论哪种方式,你结束了本地名称空间中引用是从传递func如所明确定义到deco返回的对象func标签。装饰器语法捆绑了一些额外的检查(例如确保输入和输出来自deco总是可以调用),但基本上,如果某些东西在示例1中以某种方式工作,则它将在示例2中以这种方式工作。