python wraps decorator

frominspectimportgetmembers, getargspec
fromfunctoolsimportwraps
 
defwraps_decorator(f):
    @wraps(f)
    defwraps_wrapper(*args,**kwargs):
        returnf(*args,**kwargs)
    returnwraps_wrapper
 
classSomeClass(object):
    @wraps_decorator
    defmethod(self, x, y):
        pass
 
obj=SomeClass()
forname, funcingetmembers(obj, predicate=inspect.ismethod):
    print"Member Name: %s"% name
    print"Func Name: %s"% func.func_name
    print"Args: %s"% getargspec(func)[0]
 

classmyDecorator(object):
 
    def__init__(self, fn):
        print"inside myDecorator.__init__()"
        self.fn=fn
 
    def__call__(self):
        self.fn()
        print"inside myDecorator.__call__()"
 
@myDecorator
defaFunction():
    print"inside aFunction()"
 
print"Finished decorating aFunction()"
 
aFunction()


你會發現,即使是你你用了functools的wraps,你在用getargspec時,參數也不見了。

要修正這一問,我們還得用Python的反射來解決,下面是相關的代碼:

1
2
3
4
5
6
7
8
9
10
11
12
defget_true_argspec(method):
    argspec= inspect.getargspec(method)
    args= argspec[0]
    ifargs andargs[0]=='self':
        returnargspec
    ifhasattr(method,'__func__'):
        method= method.__func__
    ifnot hasattr(method, 'func_closure')or method.func_closure is None:
        raiseException("No closure for method.")
 
    method= method.func_closure[0].cell_contents
    returnget_true_argspec(method)

當然,我相信大多數人的程序都不會去getargspec。所以,用functools的wraps應該夠用了。

class MyApp():
    def __init__(self):
        self.func_map = {}
 
    def register(self, name):
        def func_wrapper(func):
            self.func_map[name] = func
            return func
        return func_wrapper
 
    def call_method(self, name=None):
        func = self.func_map.get(name, None)
        if func is None:
            raise Exception("No function registered against - " + str(name))
        return func()
 
app = MyApp()
 
@app.register('/')
def main_page_func():
    return "This is the main page."
 
@app.register('/next_page')
def next_page_func():
    return "This is the next page."
 
print app.call_method('/')
print app.call_method('/next_page')

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章