python笔记36-装饰器之wraps
前言
前面一篇对python装饰器有了初步的了解了,但是还不够完美,领导看了后又提出了新的需求,希望运行的日志能显示出具体运行的哪个函数。
name__和__doc
__name__用于获取函数的名称,__doc__用于获取函数的docstring内容(函数的注释)
import time
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
print(func_a.__name__) # 结果 func_a
print(func_a.__doc__) # func_a --> hello
print(func_b.__name__) # func_b
print(func_b.__doc__) # func_b --> world
装饰器加函数名称日志
在装饰器里面添加2行代码,打印正在运行函数的名称和docstring内容
import time
def runtime(func):
'''runtime decorators'''
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper
@runtime
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
@runtime
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)
运行结果
running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.5008 秒
wrapper
wrapper inner fuction
从运行的结果可以看出,func_a.__name__运行的结果是wrapper, func_a.__doc__运行的结果是wrapper inner fuction。
也就是说被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),那这个问题如何解决呢?
这就需要用到functools里面的一个wraps函数了
functools
当func_a函数被装饰后,导致了一个副作用:自身的函数属性和docstring内容变成了wrapper函数的属性了。
这里需用到functools里面的一个wraps的装饰器来消除这样的副作用。
import time
from functools import wraps
def runtime(func):
'''runtime decorators'''
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
print("运行时长:%.4f 秒" % (end-start))
return f
return wrapper
只需在wrapper函数上加上@wraps(func)即可解决
运行结果
running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.5004 秒
func_a
func_a --> hello
类装饰器
带参数的装饰器,可以写成类装饰器
import time
from functools import wraps
class runtime(object):
'''runtime class decorators'''
def __init__(self, slowly=1):
self.slowly = slowly
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
'''wrapper inner fuction'''
print("running function : %s" % func.__name__)
print("docstring: %s" % func.__doc__)
start = time.time()
f = func(*args, **kwargs) # 原函数
end = time.time()
t = end-start
time.sleep((self.slowly-1)*t) # 延迟效果
new_end = time.time()
print("运行时长:%.4f 秒" % (new_end-start))
return f
return wrapper
@runtime(1.5)
def func_a(a):
'''func_a --> hello'''
print("hello"+a)
time.sleep(0.5)
return True
@runtime()
def func_b(b, c="xx"):
'''func_b --> world'''
print("world"+b+c)
time.sleep(0.8)
return True
if __name__ == '__main__':
func_a("a")
print(func_a.__name__)
print(func_a.__doc__)
运行结果
running function : func_a
docstring: func_a --> hello
helloa
运行时长:0.7522 秒
func_a
func_a --> hello
python自动化交流 QQ群:779429633
python笔记36-装饰器之wraps的更多相关文章
- python笔记 - day4-之装饰器
python笔记 - day4-之装饰器 需求: 给f1~f100增加个log: def outer(): #定义增加的log print("log") ...
- Python笔记:装饰器
装饰器 1.特点:装饰器的作用就是为已存在的对象添加额外的功能,特点在于不用改变原先的代码即可扩展功能: 2.使用:装饰器其实也是一个函数,加上@符号后放在另一个函数“头上”就实现了装饰 ...
- 20.python笔记之装饰器
装饰器 装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插 ...
- Python装饰器之functools.wraps的作用
# -*- coding: utf-8 -*- # author:baoshan def wrapper(func): def inner_function(): pass return inner_ ...
- guxh的python笔记三:装饰器
1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) tot ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- Python 中实现装饰器时使用 @functools.wraps 的理由
Python 中使用装饰器对在运行期对函数进行一些外部功能的扩展.但是在使用过程中,由于装饰器的加入导致解释器认为函数本身发生了改变,在某些情况下——比如测试时——会导致一些问题.Python 通过 ...
- Python学习笔记:装饰器
Python 装饰器的基本概念和应用 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: 封闭:已 ...
- Python函数的装饰器修复技术(@wraps)
@wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法: from ...
随机推荐
- Idea开发环境中,开发springboot类型的项目,如果只引入parent节点,不添加依赖节点,maven是不会加载springboot的任何依赖的
在SpringBoot类型的项目中,我本来是要使用pringBoot,创建一个Console项目,我原本在pom.xml中添加paren节点了,天真的认为不需要再添加其他任何依赖了,可是接下来的1个小 ...
- 【jquery】【ztree】节点添加自定义按钮、编辑和删除事件改成自己定义事件
setting添加 edit: { drag: { isCopy: false, isMove: true }, enable: true,//设置是否处于编辑状态 showRemoveBtn: sh ...
- 关于docker的scratch镜像与helloworld
关于docker的scratch镜像与helloworld 参考:https://hub.docker.com/_/scratch?tab=description 参考:https://segment ...
- Java课堂笔记1
1. Java严格区分大小写 2. 一个源文件public主类名必须和文件名完全一致 3. 命名规则严格要求,字母.数字.下划线.美元符号$.下划线_组成,其中不能以数字开头,也不能使用Java的 ...
- 【转帖】Flink 核心技术浅析(整理版)
Flink 核心技术浅析(整理版) https://www.cnblogs.com/swordfall/p/10612404.html 分类: Flink undefined 1. Flink简介 A ...
- 测试类——python编程从入门到实践
1.各种断言方法 常用断言方法: 方法 用途 assertEqual(a, b) 核实a == b assertNotEqual(a, b) 核实a != b assertTrue(x) 核实x为Tr ...
- LInux基础(04)项目设计一(理解链表管理协议的代码架构)
要设计好一个项目必须要有一个健全的代码框架 一个结构体内有数据域和处理数据的函数指针, 先实现管理链表的函数 增加节点 删除节点 清空链表 遍历节点对每个节点进行操作 再实现协议的注册 把对象s ...
- redis源码分析(二)-rio(读写抽象层)
Redis io抽象层 Redis中涉及到多种io,如socket与file,为了统一对它们的操作,redis设计了一个抽象层,即rio,使用rio可以实现将数据写入到不同的底层io,但是接口相同.r ...
- linux tomcat开机自启/nginx开机自启
修改/etc/rc.d/rc.local文件,修改完成后需执行以下指令才能正常自启动 chmod +x /etc/rc.d/rc.local #!/bin/bash # THIS FILE IS AD ...
- volatile 作用
volatile使用场景:线程间共享变量需要使用 volatile 关键字标记,确保线程能够读取到更新后的最新变量值. volatile关键字的目的是告诉虚拟机: 1.每次访问变量时,总是获取主内存的 ...