python三大器之一——装饰器详解
python的三大器指的是:装饰器、迭代器、生成器,下面就装饰器整理一下从各种资源收获的对装饰器的理解。
1.理解装饰器之前先要理解函数引用的概念
def func():print("hello world!")# 调用函数
func()# 引用函数
ret = funcprint(id(ret))
print(id(func))# 通过引用调用函数
ret()
运行结果ret和func的id相同,python里一切皆对象,函数名也是一个对象,ret是func函数的引用,它也指向func函数。或者是函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过 函数名()
调用
2.接着还得理解闭包的概念
理解:先定义一个函数,然后在该函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
# 定义一个函数
def func(num1):# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包def wrapper(num2):# 在python3中,如果要修改外部函数的变量,需要加一条申明: nonlocal 外部变量名# nonlocal num1# num += 1print("%s * %s 的积是%s" % (num1, num2, num1 * num2))return num1 * num2# 其实这里返回的就是闭包的结果,即返回内层函数的引用return wrapper# 给func函数赋值,这个20就是给参数num1
ret = func(20) # 等价于ret = wrapper# 注意这里的100其实给参数num2
print(ret(100)) # 等同于 print(wrapper(100))
运行结果将会显示 20 * 100 的积是2000
注意点:
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
3.装饰器
装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题。
假设下以下场景:
1.公司原本开发了一套软件,各个部门一起合作开发,目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即需要增加以下功能:在所有功能执行前,先进行权限验证。
2.老大把工作交给 Low B,他是这么做的:
跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。这样一来基础平台就不需要做任何修改了。太棒了,有充足的时间泡妹子…
当天Low B 被开除了…
3.老大把工作交给 Low BB,他是这么做的:
############### 基础平台提供的功能如下 ############### def f1():# 验证1# 验证2# 验证3print('f1')def f2():# 验证1# 验证2# 验证3print('f2')def f3():# 验证1# 验证2# 验证3print('f3')def f4():# 验证1# 验证2# 验证3print('f4')############### 业务部门不变 ###############
### 业务部门A 调用基础平台提供的功能### f1()
f2()
f3()
f4()### 业务部门B 调用基础平台提供的功能 ### f1()
f2()
f3()
f4()
过了一周 Low BB 被开除了…
4.老大把工作交给 Low BBB,他是这么做的:
只对基础平台的代码进行重构,其他业务部门无需做任何修改
############### 基础平台提供的功能如下 ############### def check_login():# 验证1# 验证2# 验证3passdef f1():check_login()print('f1')def f2():check_login()print('f2')def f3():check_login()print('f3')def f4():check_login()print('f4')
老大看了下Low BBB 的实现,嘴角漏出了一丝的欣慰的笑,语重心长的跟Low BBB聊了个天:
5.老大说:
写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块
- 开放:对扩展开发
如果将开放封闭原则应用在上述需求中,那么就不允许在函数 f1 、f2、f3、f4的内部进行修改代码,老板就给了Low BBB一个实现方案:
def w1(func):def inner():# 验证1# 验证2# 验证3func()return inner@w1
def f1():print('f1')
@w1
def f2():print('f2')
@w1
def f3():print('f3')
@w1
def f4():print('f4')
对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数 f1 f2 f3 f4 之前都进行【验证】操作,并且其他业务部门无需做任何操作。
4.详解装饰器
4.1 装饰器执行流程
4.2 带多个参数的装饰器
例如记录某个函数的执行时间
import time
def timer(func):def inner(*args,**kwargs):start = time.time()re = func(*args,**kwargs)print(time.time() - start)return rereturn inner@timer #==> func2 = timer(func2)
def func2(a):print('in func2 and get a:%s'%(a))return 'fun2 over'func2('aaaaaa')
print(func2('aaaaaa'))
4.3 给装饰器带参数
def outer(flag):def timer(func):def inner(*args,**kwargs):if flag:print('''执行函数之前要做的''')re = func(*args,**kwargs)if flag:print('''执行函数之后要做的''')return rereturn innerreturn timer
# 下面的装饰过程
# 1. 调用outer(False)
# 2. 将步骤1得到的返回值,即timer返回, 然后timer(func),这里的func指向定义的func函数
# 3. 将timer(func)的结果返回,即inner
# 4. 让func = inner,即func现在指向inner
@outer(False)
def func(): print(111)
func()
调用时候的func()可以理解为:func() ====> outer(Flase)(func)()
4.4装饰器的功能:
在不修改原函数及其调用方式的情况下对原函数功能进行扩展。
4.5.装饰器应用场景:
(1)引入日志
(2)函数执行时间统计
(3)执行函数前预备处理
(4)执行函数后清理功能
(5)权限校验等场景
(6)缓存
4.6 functools的应用
正常我们情况下查看函数的一些信息的方法在此处都会失效
def outer(func):def inner(*args,**kwargs):"""hello world"""return func(*args,**kwargs)return inner@outer
def index():'''你好,世界'''print('hello world!')print("函数注释:%s" % index.__doc__) #查看函数注释的方法
print("函数名:%s" % index.__name__) #查看函数名的方法
上述代码返回的结果是:
很显然,这不是我们需要的结果。我们希望得到的是被装饰的函数的函数名和注释。
- functools的wraps能够将原有的函数名返回,需要使用functools.wraps在装饰器中的函数上把传进来的这个函数进行一个包裹,这样就不会丢失原来的函数的__name__等属性.
from functools import wrapsdef outer(func):@wraps(func)def inner(*args,**kwargs):"""hello world"""return func(*args,**kwargs)return inner@outer
def index():'''你好,世界'''print('hello world!')print("函数注释:%s" % index.__doc__) #查看函数注释的方法
print("函数名:%s" % index.__name__) #查看函数名的方法
运行结果为:
5.类装饰器
class Test(object):def __init__(self, func):print("---初始化---")print("func name is %s"%func.__name__)self.__func = funcdef __call__(self):print("---装饰器中的功能---")self.__func()
#说明:
#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
# 并且会把test这个函数名当做参数传递到__init__方法中
# 即在__init__方法中的属性__func指向了test指向的函数
#
#2. test指向了用Test创建出来的实例对象
#
#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#
#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
@Test
def test():print("----test---")
test()
showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"
运行结果如下:
---初始化---
func name is test
---装饰器中的功能---
----test---
python三大器之一——装饰器详解相关推荐
- python重难点之装饰器详解
背景 虽然之前看过装饰器的相关内容,但是今天想起来,一直没有好好总结一下,所以特地记录下关于装饰器的一系列用法. 要想理解装饰器首先要明确颇python中的三个概念: 1.一切函数皆为对象 2.高阶函 ...
- Python 装饰器详解(下)
Python 装饰器详解(下) 转自:https://blog.csdn.net/qq_27825451/article/details/84627016,博主仅对其中 demo 实现中不适合pyth ...
- Python 装饰器详解(中)
Python 装饰器详解(中) 转自:https://blog.csdn.net/qq_27825451/article/details/84581272,博主仅对其中 demo 实现中不适合pyth ...
- Python 装饰器详解(上)
Python 装饰器详解(上) 转自:https://blog.csdn.net/qq_27825451/article/details/84396970,博主仅对其中 demo 实现中不适合pyth ...
- 技术图文:Python的属性装饰器详解
背景 我们在以前的一篇图文 Python基础 – Task10. 类与对象 中介绍过利用property()方法既能保护类的封装特性,又能让开发者可以使用"对象.属性"的方式操作类 ...
- python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解
我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...
- 这是我见过最全面的Python装饰器详解!没有学不会这种说法
python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,才有点点开始明白了. 学习python中有什么不懂的地方,小编这 ...
- python装饰器作用和功能_这是我见过最全面的Python装饰器详解!没有学不会这种说法!...
今天的任务比较繁重,因为我们要一起来学习Python中比较重要比较牛逼比较难的装饰器. 我将会和大家一起通过代码的形式来迷你银行存款取款的功能,然后通过引入装饰器来一步一步优化代码. 废话不多说梦开始 ...
- python之装饰器详解
这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...
最新文章
- keras保存和载入模型继续训练
- 本地连接的图标要等很长时间才出来
- 那些年搞不懂的多线程、同步异步及阻塞和非阻塞(二)---概念区分
- linux清除configure文件_在Linux操作系统下自动生成Makefile的方法
- android 底部弹窗失效,Android实现从底部弹出Dialog(和PopWindow实现的效果同样)
- 笔记︱范数正则化L0、L1、L2-岭回归Lasso回归(稀疏与特征工程)
- 设计模式--组合模式C++实现
- Transformer论文阅读(一):CoTr: Efficiently Bridging CNN and Transformer for 3D Medical Image Segmentation
- 几个可以免费下载视频素材的网站[国外],希望大家喜欢[可以的话给个关注哟]
- Hibernate 的检索策略
- python视频笔记17(控制窗体)
- [转] 蝴蝶效应,青蛙现象,鳄鱼法则,鲇鱼效应,羊群效应,刺猬法则,手表定律,破窗理论,二八定律,木桶理论,马太效应,这些你都明白吗?...
- QQ群无法下载视频和图片解决方案
- 第 4 篇、Linux操作基础 | 计算机组成
- css做八边形图片有边框
- 进程间通信的方式——信号、管道、消息队列、共享内存
- linux用户密码文件为,Linux用户和密码文件格式详解
- 大数据基础课第三课 spark_core、Spark_sqlSpark_streaming
- vue3使用dplayer视频播放器
- intel主板bios设置方法
热门文章
- 软件工程基础知识--认识软件工程
- 2022年度全球职场女性境况排名:瑞典最好,韩国连续十年垫底 | 美通社头条
- 【转帖】dicom学习笔记
- 消防工程师与消防员有什么区别?
- HP加易语言数据库,全源码制作的网络验证,可运营,可自行扩展
- arm poky linux,交叉编译iMX6 contex-A9 arm-poky 一些坑
- 【LeetCode】Integer Break
- excel按颜色求和,终于有最简单的方法了,建议收藏
- BLOCK层代码分析(10)IO下发之IO下发函数总结
- Package OpenCV not found? Let’s Find It.