@wraps作用

python中的装饰器装饰过的函数其实就不是函数本身了,我们可以看看下面的例子

import time
def timmer(func):
"""timmer doc"""
def inner(*args, **kwargs):
"""inner doc"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print("函数运行时间为 %s" % (end - start))
return res
return inner @timmer
def func_test():
"""func_test doc"""
time.sleep(2)
return print(func_test.__name__) # inner
print(func_test.__doc__) # inner doc

按我们正常的思维,func_test.__name__应该拿到的就是“func_test”,所以这个结果就印证了上面的第一句话,但是这是我们加一个@wraps,就会发现好像一切都正常了:

import time
from functools import wraps
def timmer(func):
"""timmer doc"""
@wraps(func)
def inner(*args, **kwargs):
"""inner doc"""
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print("函数运行时间为 %s" % (end - start))
return res
return inner @timmer
def func_test():
"""func_test doc"""
time.sleep(2)
return print(func_test.__name__) # func_test
print(func_test.__doc__) # func_test doc

@wraps的实现原理

为了方便理解,我把源码和例子放在了一起,这样的话我们看着会方便:

import time
from functools import partial WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
'__annotations__')
WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, # inner
wrapped, # func_test
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)
"""
print('update_wrapper 执行...')
for attr in assigned:
try:
value = getattr(wrapped, attr)
except AttributeError:
pass
else:
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
# Issue #17482: set __wrapped__ last so we don't inadvertently copy it
# from the wrapped function when updating __dict__
wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
print('update_wrapper 执行结束')
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().
"""
print('wraps 执行...')
print('wraps 执行结束') # 纯粹为了打印出来的结果好理解
return partial(update_wrapper, wrapped=wrapped,
assigned=assigned, updated=updated) def timmer(func):
print('timmer 执行...') @wraps(func) # inner = update_wrapper的返回值
def inner(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print("函数运行时间为 %s" % (end - start))
return res print('timmer 执行结束') # 当然不是真正的结束,执行完下一行才结束
return inner @timmer
def func_test():
print("func_test 执行...")
time.sleep(2)
print("func_test 运行结束")
return func_test() """
打印结果如下:
timmer 执行...
wraps 执行...
wraps 执行结束
update_wrapper 执行...
update_wrapper 执行结束
timmer 执行结束
func_test 执行...
func_test 运行结束
函数运行时间为 2.0000197887420654 从打印的结果我们可以看出,@语法会在函数定义或者说模块初始化阶段(可能称呼不对,以后回来改)就执行了
"""

上面的例子中我加了很多打印,主要是为了提醒一下在func_test()函数执行之前,@语法已经执行了。

其实原理很简单,用了一个偏函数,去执行update_wrapper,真正起作用的也是这个函数,func_test执行之前,update_wrapper函数就会把inner函数的好多属性(示例中WRAPPER_ASSIGNMENTS,WRAPPER_UPDATES指向的属性 ,还有__wrapped__属性)全部其换成func_test的属性。

python@wraps实现原理的更多相关文章

  1. Python分布式爬虫原理

    转载 permike 原文 Python分布式爬虫原理 首先,我们先来看看,如果是人正常的行为,是如何获取网页内容的. (1)打开浏览器,输入URL,打开源网页 (2)选取我们想要的内容,包括标题,作 ...

  2. Python Socket通信原理

    [Python之旅]第五篇(一):Python Socket通信原理   python Socket 通信理论 socket例子 摘要:  只要和网络服务涉及的,就离不开Socket以及Socket编 ...

  3. python解释执行原理(转载)

    Python解释执行原理 转自:http://l62s.iteye.com/blog/1481421 这里的解释执行是相对于编译执行而言的.我们都知道,使用C/C++之类的编译性语言编写的程序,是需要 ...

  4. python虚拟机运行原理

    近期为了面试想要了解下python的运行原理方面的东西,奈何关于python没有找到一本类似于深入理解Java虚拟机方面的书籍,找到了一本<python源码剖析>电子书,但是觉得相对来说最 ...

  5. python程序执行原理

    Python程序的执行原理 1. 过程概述 Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后解释器一条一条执行字节码指令,从而完成程序的执行. 1.1python先把代码(.py ...

  6. Python进阶----索引原理,mysql常见的索引,索引的使用,索引的优化,不能命中索引的情况,explain执行计划,慢查询和慢日志, 多表联查优化

    Python进阶----索引原理,mysql常见的索引,索引的使用,索引的优化,不能命中索引的情况,explain执行计划,慢查询和慢日志, 多表联查优化 一丶索引原理 什么是索引:       索引 ...

  7. Hive Python Streaming的原理及写法

    在Hive中,须要实现Hive中的函数无法实现的功能时,就能够用Streaming来实现. 其原理能够理解成:用HQL语句之外的语言,如Python.Shell来实现这些功能,同一时候配合HQL语句, ...

  8. 轻松搞懂Python递归函数的原理与应用

    递归: 在函数的定义中,函数内部的语句调用函数本身. 1.递归的原理 学习任何计算机语言过程中,“递归”一直是所有人心中的疼.不知你是否听过这个冷笑话:“一个面包,走着走着饿了,于是就把自己吃了”. ...

  9. 5分钟看懂系列:Python 线程池原理及实现

    概述 传统多线程方案会使用"即时创建, 即时销毁"的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器 ...

随机推荐

  1. footer固定在页面底部的实现方法总结

    方法一:footer高度固定+绝对定位 HTML代码: <body> <header>头部</header> <main>中间内容</main&g ...

  2. iOS----------Xcode 无线调试

    环境要求: 至少Mac OSX 10.12.6 iOS 11 Xcode 9 1. ”自己的工程“ -> windows -> Device and Simulators ,打开设备和模拟 ...

  3. Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块

    Python第十五天  datetime模块 time模块   thread模块  threading模块  Queue队列模块  multiprocessing模块  paramiko模块  fab ...

  4. Java基础之入门

    写写基础,顺便回顾下,再深层次思考下哪些深入的没弄明白. Java是Sun Microsystems于1995年推出的高级编程语言  其版本 由 1.1 -> 1.2 -> 1.3 -&g ...

  5. maven中央仓库、远程仓库地址

    1.http://repo1.maven.org/maven2 (官方,速度一般) 2.http://maven.aliyun.com/nexus/content/repositories/centr ...

  6. MySQL(InnoDB)是如何处理死锁的

    MySQL(InnoDB)是如何处理死锁的 一.什么是死锁 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁. 这个就好比你有一个人质,对方有一个人质,你们俩去 ...

  7. Thermostat:双层存储结构的透明巨页内存管理机制

    这是一篇由密歇根大学的Neha Agarwal 和 Thomas F. Wenisch,发表在计算机系统顶会ASLOS的论文,Thermostat: Application-transparent P ...

  8. Linux云计算工程师

    一.Linux运维基础 二.Linux运维高级-核心知识提高 三.50台集群实战 四.200-1000台集群实战 五.shell编程企业级实战 六.数据库MySQL和NoSQL 七.LVM虚拟化和机房 ...

  9. MySQL存储引擎简单介绍

    MySQL使用的是插件式存储引擎. 主要包含存储引擎有:MyISAM,Innodb,NDB Cluster,Maria.Falcon,Memory,Archive.Merge.Federated. 当 ...

  10. pyecharts使用

    安装 pyecharts 兼容 Python2 和 Python3.目前版本为 0.1.2 pip install pyecharts 入门 首先开始来绘制你的第一个图表 from pyecharts ...