python之装饰器函数
本章内容
引入
作为一个会写函数的python开发,我们从今天开始要去公司上班了。写了一个函数,就交给其他开发用了。
def func1():
print('in func1')
季度末,公司的领导要给大家发绩效奖金了,就提议对这段日子所有人开发的成果进行审核,审核的标准是什么呢?就是统计每个函数的执行时间。
这个时候你要怎么做呀?
你一想,这好办,把函数一改:
import time
def func1():
start = time.time()
print('in func1')
print(time.time() - start) func1()
来公司半年,写了2000+函数,挨个改一遍,1个礼拜过去了,等领导审核完,再挨个给删了。。。又1个礼拜过去了。。。这是不是很闹心?
你觉得不行,不能让自己费劲儿,告诉所有开发,现在你们都在自己原本的代码上加上一句计算时间的语句?
import time
def func1():
print('in func1') start = time.time()
func1()
print(time.time() - start)
还是不行,因为这样对于开发同事来讲实在是太麻烦了。
那怎么办呢?你灵机一动,写了一个timer函数。。。
import time
def timer(func):
start = time.time()
func()
print(time.time() - start) def func1():
print('in func1') def func2():
print('in func2') timer(func1)
timer(func2)
这样看起来是不是简单多啦?不管我们写了多少个函数都可以调用这个计时函数来计算函数的执行时间了。。。尽管现在修改成本已经变得很小很小了,但是对于同事来说还是改变了这个函数的调用方式,假如某同事因为相信你,在他的代码里用你的方法用了2w多次,那他修改完代码你们友谊的小船也就彻底地翻了。
你要做的就是,让你的同事依然调用func1,但是能实现调用timer方法的效果。
import time
def timer(func):
start = time.time()
func()
print(time.time() - start) def func1():
print('in func1') func1 =timer #要是能这样的就完美了。。。可惜报错
func1()
非常可惜,上面这段代码是会报错的,因为timer方法需要传递一个func参数,我们不能在赋值的时候传参,因为只要执行func1 = timer(func1),timer方法就直接执行了,下面的那句func1根本就没有意义。到这里,我们的思路好像陷入了僵局。。。
装饰器的形成过程
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)
func1()
装饰器——简单版1
忙活了这么半天,终于初具规模了!现在已经基本上完美了,唯一碍眼的那句话就是还要在做一次赋值调用。。。
你觉得碍眼,python的开发者也觉得碍眼,所以就为我们提供了一句语法糖来解决这个问题!
import time
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner @timer #==> func1 = timer(func1)
def func1():
print('in func1') func1()
装饰器——语法糖
到这里,我们可以简单的总结一下:
装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
还有最后一个问题要解决,刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner @timer
def func1(a):
print(a) func1(1)
装饰器——带参数的装饰器
其实装饰带参的函数并不是什么难事,但假如你有两个函数,需要传递的参数不一样呢?
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner @timer #==> func1 = timer(func1)
def func1(a,b):
print('in func1') @timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over' func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
装饰器——成功hold住所有函数传参
现在参数的问题已经完美的解决了,可是如果你的函数是有返回值的呢?
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner @timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over' func2('aaaaaa')
print(func2('aaaaaa'))
装饰器——带返回值的装饰器
刚刚那个装饰器已经非常完美了,但是正常我们情况下查看函数的一些信息的方法在此处都会失效
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__)
装饰器——wraps demo
开放封闭原则
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):
return func(*args,**kwargs)
return wrapper
装饰器的固定格式——wraps版
带参数的装饰器
假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?
一个一个的取消掉? 没日没夜忙活3天。。。
过两天你领导想通了,再让你加上。。。
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)
def func():
print(111) func()
带参数的装饰器
python之装饰器函数的更多相关文章
- python学习——装饰器函数
一.装饰器函数的作用是什么 答:装饰器函数是在不修改原函数及其调用方式的情况下对原函数功能进行扩展 对于搞python开发的人来说,函数占据了至关重要的地位.都说学好函数你就可以去找工作了,好了,假如 ...
- python递归,装饰器,函数, 高阶函数
在函数内部,可以调用其它函数,如果一个函数在内部调用自身本身,这个函数就是递归函数 递归特性:1.必须有一个明确的结束条件 2.每次进入更深一层递归时,问题规模比上次递归都有所减少(10-8-5等) ...
- python之装饰器(函数)
1. 装饰器 遵循的原则: 开闭原则: 对功能的扩展开放 对代码的修改是封闭 # 通用装饰器写法 # 存在的意义: 在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能. def wrapp ...
- 【Python】装饰器实现日志记录
好的日志对一个软件的重要性是显而易见的.如果函数的入口都要写一行代码来记录日志,这种方式实在是太低效了,但一直没有找到更好的方法.后来用python写一些软件,了解到python的装饰器功能时,突然人 ...
- python基础篇_004_装饰器函数
python装饰器函数 1.装饰器函数引导 功能:计算函数执行时长 import time """ 方式一: 函数首位添加时间,差值就是函数执行时间 缺点:每个函数都要加 ...
- python基础 (装饰器,内置函数)
https://docs.python.org/zh-cn/3.7/library/functions.html 1.闭包回顾 在学习装饰器之前,可以先复习一下什么是闭包? 在嵌套函数内部的函数可以使 ...
- python基础(8)-装饰器函数&进阶
从小例子进入装饰器 统计一个函数执行耗时 原始版本 import time # time模块有提供时间相关函数 def do_something(): print("do_something ...
- 如何用python的装饰器定义一个像C++一样的强类型函数
Python作为一个动态的脚本语言,其函数在定义时是不需要指出参数的类型,也不需要指出函数是否有返回值.本文将介绍如何使用python的装饰器来定义一个像C++那样的强类型函数.接下去,先介绍 ...
- python通过装饰器检查函数参数的数据类型的代码
把内容过程中比较常用的一些内容记录起来,下面内容段是关于python通过装饰器检查函数参数的数据类型的内容. def check_accepts(f): assert len(types) == f. ...
随机推荐
- 转载 用Python实现设计模式——工厂模式
转载自 SegmentFault作者 夏秋, https://segmentfault.com/a/1190000013053013 非常感谢这位作者的深入浅出的讲解. 前言 工厂模式,顾名思义就是我 ...
- Python函数——闭包延迟绑定
前言 请看下面代码 def multipliers(): return [lambda x : i*x for i in range(4)] print ([m(2) for m in multipl ...
- [EXP]Huawei Router HG532e - Command Execution
#!/bin/python ''' Author : Rebellion Github : @rebe11ion Twitter : @rebellion ''' import urllib2,req ...
- 第八章:四大组件之Content Provider
前言 Content Provider——Android四大组件之一. 本文要点 1.Content Provider简介 2.URI简介 3.如何访问Content Provider中数据 一.Co ...
- spring framework核心框架体系结构(转载)
作者:Dreawer 很多人都在用spring开发java项目,但是配置maven依赖的时候并不能明确要配置哪些spring的jar,经常是胡乱添加一堆,编译或运行报错就继续配置jar依赖,导致spr ...
- Vue + Element UI 实现权限管理系统 前端篇(十六):系统备份还原
系统备份还原 在很多时候,我们需要系统数据进行备份还原.我们这里就使用MySql的备份还原命令实现系统备份还原的功能. 后台接口准备 系统备份还原是对数据库的备份还原,所以必须有后台接口的支持,我们准 ...
- mysql表分区实战
一,什么是数据库分区以mysql为例,mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面 (可以通过my.cnf中的datadir来查看),一张表主要对应着三个文件 ...
- (转)深度学习目标检测指标mAP
深度学习目标检测指标mAP https://github.com/rafaelpadilla/Object-Detection-Metrics 参考上面github链接中的readme,有详细描述
- Crypto++应用:非对称加密RSA
1,非对称加密RSA: (1)乙方生成两把密钥(公钥和私钥).公钥是公开的,任何人都可以获得,私钥则是保密的. (2)甲方获取乙方的公钥,然后用它对信息加密. (3)乙方得到加密后的信息,用私钥解密. ...
- C++ QT中自定义控件的简单创建
为了给控件添加自定义的方法以及重绘控件,我们需要自定义控件来达到自己希望的结果,网上的自定义控件文章比较少,并且过程比较粗略. 此教程以中文版的QT Creator进行介绍 首先我们创建一个新的项目, ...