python 理解functools.wraps

xiaoxiao2021-02-28  83

先复习下装饰器 # coding=utf-8 def logged(func): def with_logging(*args, **kwargs): """ 哈哈哈,这里是with_logging :param args: :param kwargs: :return: """ print func.__name__, " was called..." return func(*args, **kwargs) return with_logging @logged def f(x): """ 哈哈,这是f :param x: :return: """ return x + x * x print f.__name__ print f.__doc__ 打印结果是: (venv) ➜ myApp git:(v1.6_dev) ✗ python 1.py with_logging 哈哈哈,这里是with_logging :param args: :param kwargs: :return: 理论上这是不对的,因为函数f的信息已经获取不到了。。都被with_logging取代了。 解决方案: # coding=utf-8 import functools def logged(func): @functools.wraps(func) def with_logging(*args, **kwargs): """ 哈哈哈,这里是with_logging :param args: :param kwargs: :return: """ print func.__name__, " was called..." return func(*args, **kwargs) return with_logging @logged def f(x): """ 哈哈,这是f :param x: :return: """ return x + x * x print f.__name__ print f.__doc__ 打印结果是: (venv) ➜ myApp git:(v1.6_dev) ✗ python 1.py f 哈哈,这是f :param x: :return: 以上是别的教程写的解决方案,突然对这个functools.wraps()有点兴趣,它到底是如何做到的呢? functools.warp方法就是把被wrapped的函数的属性传递给wrapper的函数。 WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Update a wrapper function to look like the wrapped function wrapper is the function to be updated wrapped is the original function assigned is a tuple naming the attributes assigned directly from the wrapped function to the wrapper function (defaults to functools.WRAPPER_ASSIGNMENTS) updated is a tuple naming the attributes of the wrapper that are updated with the corresponding attribute from the wrapped function (defaults to functools.WRAPPER_UPDATES) """ for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Return the wrapper so this can be used as a decorator via partial() return wrapper def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Decorator factory to apply update_wrapper() to a wrapper function Returns a decorator that invokes update_wrapper() with the decorated function as the wrapper argument and the arguments to wraps() as the remaining arguments. Default arguments are as for update_wrapper(). This is a convenience function to simplify applying partial() to update_wrapper(). """ return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) 这个乍一看不是很理解,这个怎么和普通的装饰器不大一样呀。普通的长得像: def out_wrapper(func): def in_wrapper(*args, **kwargs): print ‘in_wrapper’ return func(*args, **kwargs) return in_wrapper 不过剥丝抽茧,先去除注释: WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) return wrapper def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) 嗯,看起来简单清爽多了。考虑到偏函数,上面代码可以转成: WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): for attr in assigned: setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) return wrapper def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): def in_wrapper(wrapper, wrapped=wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return update_wrapper(wrapper, wrapped=wrapped, assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES) return in_wrapper 一般带参数的装饰器,是三层的,类似: def wrapper(x): def out_wrapper(func): def in_wrapper(*args, **kwargs): print ‘in_wrapper’ return func(*args, **kwargs) return in_wrapper return out_wrapper 虽然长得不一样,但思路就是返回一个能包装函数的函数变量,这帮作者写代码真是骚。 end...
转载请注明原文地址: https://www.6miu.com/read-32485.html

最新回复(0)