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三大器之一——装饰器详解相关推荐

  1. python重难点之装饰器详解

    背景 虽然之前看过装饰器的相关内容,但是今天想起来,一直没有好好总结一下,所以特地记录下关于装饰器的一系列用法. 要想理解装饰器首先要明确颇python中的三个概念: 1.一切函数皆为对象 2.高阶函 ...

  2. Python 装饰器详解(下)

    Python 装饰器详解(下) 转自:https://blog.csdn.net/qq_27825451/article/details/84627016,博主仅对其中 demo 实现中不适合pyth ...

  3. Python 装饰器详解(中)

    Python 装饰器详解(中) 转自:https://blog.csdn.net/qq_27825451/article/details/84581272,博主仅对其中 demo 实现中不适合pyth ...

  4. Python 装饰器详解(上)

    Python 装饰器详解(上) 转自:https://blog.csdn.net/qq_27825451/article/details/84396970,博主仅对其中 demo 实现中不适合pyth ...

  5. 技术图文:Python的属性装饰器详解

    背景 我们在以前的一篇图文 Python基础 – Task10. 类与对象 中介绍过利用property()方法既能保护类的封装特性,又能让开发者可以使用"对象.属性"的方式操作类 ...

  6. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  7. 这是我见过最全面的Python装饰器详解!没有学不会这种说法

    python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,才有点点开始明白了. 学习python中有什么不懂的地方,小编这 ...

  8. python装饰器作用和功能_这是我见过最全面的Python装饰器详解!没有学不会这种说法!...

    今天的任务比较繁重,因为我们要一起来学习Python中比较重要比较牛逼比较难的装饰器. 我将会和大家一起通过代码的形式来迷你银行存款取款的功能,然后通过引入装饰器来一步一步优化代码. 废话不多说梦开始 ...

  9. python之装饰器详解

    这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...

最新文章

  1. keras保存和载入模型继续训练
  2. 本地连接的图标要等很长时间才出来
  3. 那些年搞不懂的多线程、同步异步及阻塞和非阻塞(二)---概念区分
  4. linux清除configure文件_在Linux操作系统下自动生成Makefile的方法
  5. android 底部弹窗失效,Android实现从底部弹出Dialog(和PopWindow实现的效果同样)
  6. 笔记︱范数正则化L0、L1、L2-岭回归Lasso回归(稀疏与特征工程)
  7. 设计模式--组合模式C++实现
  8. Transformer论文阅读(一):CoTr: Efficiently Bridging CNN and Transformer for 3D Medical Image Segmentation
  9. 几个可以免费下载视频素材的网站[国外],希望大家喜欢[可以的话给个关注哟]
  10. Hibernate 的检索策略
  11. python视频笔记17(控制窗体)
  12. [转] 蝴蝶效应,青蛙现象,鳄鱼法则,鲇鱼效应,羊群效应,刺猬法则,手表定律,破窗理论,二八定律,木桶理论,马太效应,这些你都明白吗?...
  13. QQ群无法下载视频和图片解决方案
  14. 第 4 篇、Linux操作基础 | 计算机组成
  15. css做八边形图片有边框
  16. 进程间通信的方式——信号、管道、消息队列、共享内存
  17. linux用户密码文件为,Linux用户和密码文件格式详解
  18. 大数据基础课第三课 spark_core、Spark_sqlSpark_streaming
  19. vue3使用dplayer视频播放器
  20. intel主板bios设置方法

热门文章

  1. 软件工程基础知识--认识软件工程
  2. 2022年度全球职场女性境况排名:瑞典最好,韩国连续十年垫底 | 美通社头条
  3. 【转帖】dicom学习笔记
  4. 消防工程师与消防员有什么区别?
  5. HP加易语言数据库,全源码制作的网络验证,可运营,可自行扩展
  6. arm poky linux,交叉编译iMX6 contex-A9 arm-poky 一些坑
  7. 【LeetCode】Integer Break
  8. excel按颜色求和,终于有最简单的方法了,建议收藏
  9. BLOCK层代码分析(10)IO下发之IO下发函数总结
  10. Package OpenCV not found? Let’s Find It.