day11 python之函数装饰器
一,什么是装饰器?
装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
二,装饰器的形成过程。
现在我有一个需求,我想让你测试这个函数的执行时间,在不改变这个函数代码的情况下:
import time def func1():
print('in func1') def timer(func):
start = time.time()
func()
print(time.time() - start) timer(func1)
上面的代码输出了func1()函数的运行时间,但是我们计算func1()函数的运行时间时,需要调用的是timer(func)函数
有没有办法直接调用func1()函数就能计算func1()函数运行时间呢?
如果让 func1 = timer 呢? 可是timer()函数需要一个函数参数,而我们的 func1 是不需要参数的,显然不行
那该怎么实现呢? 换个思路, timer不能赋值给func1,但是我们可以给timer指定一个函数返回值,将他赋值给func1
那么执行 func1() 时就相当于执行 这个用来赋值的函数.而这个函数在timer()函数内,可以调用timer()函数的参数func
如下所以,我们使用闭包的方法解决了这个问题
import time # 引入时间模块 def func1(): # 要测试执行时间的函数
print('in func1') def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner func1 = timer(func1) # time()的返回值是inner
func1() # func1()==inner()
在上面的方法中,timer()函数就是我们的装饰器函数,func1()是被装饰的.
但是,在上面的例子中,func1()是没有返回值和参数的,要是带上参数返回值呢?
import time # 引入时间模块 def func1(a,b=1): # 要测试执行时间的函数
print('in func1')
return 'func1的返回值' def timer(func):
def inner(*args,**kwargs): # 设置为可以接受任意参数
start = time.time()
set = func(*args,**kwargs)
print(time.time() - start)
return set # 返回func函数原本的返回值
return inner func1 = timer(func1) # time()的返回值是inner
func1(a,b=3) # func1(a,b=3)==inner(a,b=3)
但是如果有多个函数,我都想让你测试他们的执行时间,你每次是不是都得func1 = timer(func1)?这样还是有点麻烦,因为这些函数的函数名可能是不相同,有func1,func2,graph,等等,所以更简单的方法,python给你提供了,那就是语法糖。
@timer # == func1 = timer(func1)
上面的装饰器已经非常完美了,但是有我们正常情况下查看函数信息的方法在此处都会失效:
def index():
'''这是一个主页信息'''
print('from index') print(index.__doc__) #查看函数注释的方法
print(index.__name__) #查看函数名的方法
如何解决这个问题呢?
from functools import wraps def deco(func):
@wraps(func) #加在最内层函数正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper @deco
def index():
'''哈哈哈哈'''
print('from index') print(index.__doc__)
print(index.__name__)
三,开放封闭原则。
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
四,装饰器的主要功能和固定结构。
def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner
from functools import wraps def deco(func):
@wraps(func) #加在最内层函数正上方,确保查看函数信息的方法可用
def wrapper(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return wrapper
装饰器的固定格式--wraps版
五,带参数的装饰器。
注意@outer(False)的用法
上面的@timer 相当于 func = timer(func) , 返回值是 inner
下面的@outer(False) 相当于 func = outer(False)(func) ,返回值仍是 inner
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer @outer(False) #此处相较上面的语法糖,多了括号和参数.@outer(False)==>func=outer(False)(func),返回值仍是inner
def func():
print(111) func()
六,多个装饰器装饰一个函数。
def wrapper1(func):
def inner():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner def wrapper2(func):
def inner():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner @wrapper2
@wrapper1
def f():
print('in f') f()
day11 python之函数装饰器的更多相关文章
- python基础—函数装饰器
python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...
- Day11 Python基础之装饰器(高级函数)(九)
在python中,装饰器.生成器和迭代器是特别重要的高级函数 https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...
- python基础-----函数/装饰器
函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...
- Decorator——Python初级函数装饰器
最近想整一整数据分析,在看一本关于数据分析的书中提到了(1)if __name__ == '__main__' (2)列表解析式 (3)装饰器. 先简单描述一下前两点,再详细解说Python初级的函数 ...
- python 复习函数 装饰器
# 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...
- python 匿名函数&装饰器
匿名函数 关键字lambda表示匿名函数,冒号前面的x表示函数参数匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果. >>> list(map(l ...
- python闭包函数&装饰器
一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...
- Python之函数装饰器
在实际中,我们可能需要在不改变函数源代码和调用方式的情况下,为函数添加一些新的附加功能,能够实现这种功能的函数我们将其称之为装饰器.装饰器本质上其实还是是一个函数,用来装饰其它函数,为函数添加一些附加 ...
- python 之 函数 装饰器
5.8 装饰器 1 开放封闭原则 软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的 也就是说我们必须找到一种解决方案: 能够在不修改一个功能源代码以及调用方式的前提 ...
随机推荐
- OE1、OE2、ON1、ON2路由有什么区别?
OSPF的路由类型: 1 .O 域内路由 2 .O/A 域间路由 3 .OE1 域外路由,会累加METRIC值(默认20) 4 .OE2 域外路由,不累加METRIC值(默认20),由外部 ...
- ASCII码与unicode字符集
问题1:为什么需要字符ASCII码.unicode码等等???它们到底有什么作用? 首先要明白一个事实:在计算机中只能用一系列存储着的0和1,当我们把一个字符存放在计算机时,我们是如何表示常用的字符呢 ...
- 一个有界任务队列的thradpoolexcutor, 直接捕获错误日志
基于官方的需要改版 1.改为有界,官方是吧所有任务添加到线程池的queue队列中,这样内存会变大,也不符合分布式的逻辑(会把中间件的所有任务一次性取完,放到本地的queue队列中,导致分布式变差) 2 ...
- Flask学习笔记(2)--最简单的小应用
0x01 第一个小程序 PyCharm新建一个flask项目,第一个小程序,我们来看一下 #引入flask类 from flask import Flask #将Flask对象实例化 app = Fl ...
- 排序算法--插入排序(Insertion Sort)_C#程序实现
排序算法--插入排序(Insertion Sort)_C#程序实现 排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来 ...
- CentOS7.X安装LMMP环境Nginx+PHP+Mysql详解
前言: 作为PHP开发者,我们常用的线上环境就是LNMP,合理的搭建也是必须掌握的技能,下面就利用源码的方式详细介绍下LNMP环境Nginx+PHP+Mysql的详细搭建步骤: 版本说明: Nginx ...
- hibernate10--命名查询
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hiber ...
- python中print(obj) 与sys.stdout.write()的区别
print(obj) 其实等价于sys.stdout.write(obj+\n),而\r表示回到行首,所以需要输出进度条时可以用以下代码 rate = float(has_sent) / float( ...
- 14 CSS题目附答案
转载自公众号:web前端开发 原文题目:45道CSS基础面试题(附答案) 1. 介绍一下标准的CSS的盒子模型?与低版本IE的盒子模型有什么不同的? 标准盒子模型:宽度=内容的宽度(content) ...
- Ice_cream's world I(并查集成环)
Problem Description ice_cream's world is a rich country, it has many fertile lands. Today, the queen ...