欢迎各位兄弟 发布技术文章
这里的技术是共享的
到这里,我相信你应该了解了整个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 wrapsdef hello(fn): @wraps(fn) def wrapper(): print "hello, %s" % fn.__name__ fn() print "goodby, %s" % fn.__name__ return wrapper@hellodef foo(): '''foo help doc''' print "i am foo" passfoo()print foo.__name__ #输出 fooprint 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, getargspecfrom functools import wrapsdef wraps_decorator(f): @wraps(f) def wraps_wrapper(*args, **kwargs): return f(*args, **kwargs) return wraps_wrapperclass SomeClass(object): @wraps_decorator def method(self, x, y): passobj = 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应该够用了。