欢迎各位兄弟 发布技术文章
这里的技术是共享的
到这里,我相信你应该了解了整个Python的decorator的原理了。
相信你也会发现,被decorator的函数其实已经是另外一个函数了,对于最前面那个hello.py的例子来说,如果你查询一下foo.__name__的话,你会发现其输出的是“wrapper”,而不是我们期望的“foo”,这会给我们的程序埋一些坑。所以,Python的functool包中提供了一个叫wrap的decorator来消除这样的副作用。下面是我们新版本的hello.py。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from functools import wraps def hello(fn): @wraps (fn) def wrapper(): print "hello, %s" % fn.__name__ fn() print "goodby, %s" % fn.__name__ return wrapper @hello def foo(): '''foo help doc''' print "i am foo" pass foo() print foo.__name__ #输出 foo print foo.__doc__ #输出 foo help doc |
当然,即使是你用了functools的wraps,也不能完全消除这样的副作用。
来看下面这个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from inspect import getmembers, getargspec from functools import wraps def wraps_decorator(f): @wraps (f) def wraps_wrapper( * args, * * kwargs): return f( * args, * * kwargs) return wraps_wrapper class SomeClass( object ): @wraps_decorator def method( self , x, y): pass obj = SomeClass() for name, func in getmembers(obj, predicate = inspect.ismethod): print "Member Name: %s" % name print "Func Name: %s" % func.func_name print "Args: %s" % getargspec(func)[ 0 ] # 输出: # Member Name: method # Func Name: method # Args: [] |
你会发现,即使是你你用了functools的wraps,你在用getargspec时,参数也不见了。
要修正这一问,我们还得用Python的反射来解决,下面是相关的代码:
1 2 3 4 5 6 7 8 9 10 11 12 | def get_true_argspec(method): argspec = inspect.getargspec(method) args = argspec[ 0 ] if args and args[ 0 ] = = 'self' : return argspec if hasattr (method, '__func__' ): method = method.__func__ if not hasattr (method, 'func_closure' ) or method.func_closure is None : raise Exception( "No closure for method." ) method = method.func_closure[ 0 ].cell_contents return get_true_argspec(method) |
当然,我相信大多数人的程序都不会去getargspec。所以,用functools的wraps应该够用了。