python@wraps实现原理
@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实现原理的更多相关文章
- Python分布式爬虫原理
转载 permike 原文 Python分布式爬虫原理 首先,我们先来看看,如果是人正常的行为,是如何获取网页内容的. (1)打开浏览器,输入URL,打开源网页 (2)选取我们想要的内容,包括标题,作 ...
- Python Socket通信原理
[Python之旅]第五篇(一):Python Socket通信原理 python Socket 通信理论 socket例子 摘要: 只要和网络服务涉及的,就离不开Socket以及Socket编 ...
- python解释执行原理(转载)
Python解释执行原理 转自:http://l62s.iteye.com/blog/1481421 这里的解释执行是相对于编译执行而言的.我们都知道,使用C/C++之类的编译性语言编写的程序,是需要 ...
- python虚拟机运行原理
近期为了面试想要了解下python的运行原理方面的东西,奈何关于python没有找到一本类似于深入理解Java虚拟机方面的书籍,找到了一本<python源码剖析>电子书,但是觉得相对来说最 ...
- python程序执行原理
Python程序的执行原理 1. 过程概述 Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后解释器一条一条执行字节码指令,从而完成程序的执行. 1.1python先把代码(.py ...
- Python进阶----索引原理,mysql常见的索引,索引的使用,索引的优化,不能命中索引的情况,explain执行计划,慢查询和慢日志, 多表联查优化
Python进阶----索引原理,mysql常见的索引,索引的使用,索引的优化,不能命中索引的情况,explain执行计划,慢查询和慢日志, 多表联查优化 一丶索引原理 什么是索引: 索引 ...
- Hive Python Streaming的原理及写法
在Hive中,须要实现Hive中的函数无法实现的功能时,就能够用Streaming来实现. 其原理能够理解成:用HQL语句之外的语言,如Python.Shell来实现这些功能,同一时候配合HQL语句, ...
- 轻松搞懂Python递归函数的原理与应用
递归: 在函数的定义中,函数内部的语句调用函数本身. 1.递归的原理 学习任何计算机语言过程中,“递归”一直是所有人心中的疼.不知你是否听过这个冷笑话:“一个面包,走着走着饿了,于是就把自己吃了”. ...
- 5分钟看懂系列:Python 线程池原理及实现
概述 传统多线程方案会使用"即时创建, 即时销毁"的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器 ...
随机推荐
- mysql索引结构及其原理
1.定义 索引是一种数据结果,帮助提高获取数据的速度 为了提高查找速度,有很多查询优化算法.但是每种查找算法都只能应用于特定数据结构之上. 索引就是数据库创建的满足特定查找算法的数据结构,这些数据结构 ...
- flex练习---纵横中文网
采用 flexbox 弹性容器进行布局,只做练习用. 浏览器打开时切换到手机模式. 样本地址: http://tpl.zhuamimi.cn/%E6%89%8B%E6%9C%BA%E7%AB%AF%E ...
- 演示Eclipse插件实现代码提示和补全
续上文重拾< 两周自制脚本语言 >- Eclipse插件实现语法高亮, 但仅达到了演示Eclipse本身功能的程度, 与石头语言并无直接联系. 源码库相同, 仍在同一插件. 演示效果如下: ...
- 基于Html5 Plus + Vue + Mui 移动App开发(三)-文件操作(读取、保存、更新数据)
随着手机的发展,现在越来越多的人选择在手机上看书.无论是专业书籍.文学.英语还是网络小说,在手机上看新闻成了人们处理零碎时间的办法.在智能手机里安装一个资讯APP,可以随时.随地查看自己想看的资讯 ...
- (四) Keras Dropout和正则化的使用
视频学习来源 https://www.bilibili.com/video/av40787141?from=search&seid=17003307842787199553 笔记 使用drop ...
- python turtle 书写新年快乐
文章链接:https://mp.weixin.qq.com/s/xYSKH_KLYfooIoelJH02Cg 农历2018年的最后一篇文章,踏上回家的征途前,推荐一个Python的三方库turtle, ...
- spring javaconfig druidsource
package dataConfig; import java.sql.SQLException; import org.springframework.context.annotation.Bean ...
- 新浪短连接API免登陆免认证实例
string source = "source=2849184197"; // APP Key,这个可以根据自己需要去网上搜索 string url_long = $"u ...
- oracle有三种类型的异常错误: 预定义 ( Predefined )错误里面的常见错误
oracle有三种类型的异常错误: 预定义 ( Predefined )错误, 非预定义 ( Predefined )错误, 用户定义(User_define) 错误 预定义 ( Predefined ...
- centos6.5搭建hadoop完整教程
https://blog.csdn.net/hanzl1/article/details/79040380 博客地址http://blog.csdn.net/pucao_cug/article/det ...