1、装饰器的定义

装饰器的本质就是函数,用来装饰其它函数,就是为其它函数添加附加功能。

装饰器原则如下:

不能修改被装饰的函数的源代码

不能修改被装饰的函数的调用方式

2、实现装饰器知识储备

函数即变量

1 defbar():2 print("in the bar")3 deffoo():4 print("in the foo")5 bar()6

7 foo()8

9 print("----------分割线-----------")10

11 deffoo1():12 print("in the foo")13 bar1()14 defbar1():15 print("in the bar")16

17 foo1()18

19 print("----------分割线-----------")20 #这样会报错

21 #def foo2():

22 #print("in the foo")

23 #bar2()

24 #foo2()

25 #def bar2():

26 #print("in the bar")

高阶函数

把一个函数名当作实参传递给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

1 importtime2

3 defbar1():4 time.sleep(3)5 print("in the bar")6

7 deftest2(func):8 start_time =time.time()9 func() #相当于运行bar1()

10 stop_time =time.time()11 print("total run time %s" %(stop_time -start_time))12

13 test2(bar1)

返回值中包含函数名(不能修改函数的调用方式)

1 defbar2():2 time.sleep(3)3 print("in the bar2")4

5 deftest3(func):6 print(func)7 returnfunc8

9 print(test3(bar2)) #获取的是内存地址

10

11 res =test3(bar2)12 res()

嵌套函数

1 deffoo():2 print("in the foo")3 defbar():4 print("in the bar")5 bar() #局部变量只能在其作用域内调用

6

7 foo()

1 x =02 defgrandpa():3 x = 1

4 defdad():5 x = 2

6 defson():7 x = 3

8 print(x) #最终打印结果为3

9 son()10 dad()11 grandpa()

高阶函数 + 嵌套函数 --》装饰器

1 importtime2

3

4 deftimer(func):5 defdeco():6 start_time =time.time()7 func()8 stop_time =time.time()9 print("total time is %s" % (stop_time -start_time))10 return deco #返回deco()的内存地址

11

12

13 deftest1():14 time.sleep(3)15 print("in the test1")16

17

18 deftest2():19 time.sleep(3)20 print("in the test2")21

22 #以下可直接用装饰器语法代替

23 timer(test1) #test1的内存地址赋值给func,返回deco()的内存地址

24 print(timer(test1)) #返回deco()的内存地址

25 test1 = timer(test1) #内存地址赋值给test1

26 test1() #相当于执行deco()

27

28 timer(test2)29 test2 =timer(test2)30 test2()31

32 print("---------我是分隔符---------")33

34

35 #装饰器语法如下。(和上面引用的效果一样)

36 @timer #相当于test1 = timer(test1)

37 deftest1():38 time.sleep(3)39 print("in the test1")40

41

42 @timer #相当于test1 = timer(test1)43 deftest2():44 time.sleep(3)45 print("in the test2")46

47

48 test1()49 test2()

3、动态参数装饰器

deftimer(bar):def inner(*args, **kwargs):

start_time=time.time()

foo_ret= bar(*args, **kwargs)

end_time=time.time()

used_time= end_time -start_timeprint(used_time)returnfoo_retreturninner

@timerdef foo(*args, **kwargs):

time.sleep(1)print("我的参数:", args, kwargs)print("我的运行时间:")return "我的返回值"ret= foo("动态参数装饰器", (1, 2), name="Druid", age=18)print(ret)

输出结果如下:

4、装饰器原理图解

4.1 被装饰函数没有返回值

4.2 被装饰函数有返回值

注意:第二步仅为过程分析量,不作为真实的执行顺序。

5、装饰器固定格式

装饰器的固定格式如下例所示:

defwrapper(func):"""该函数为装饰器函数

:param func: 这里的func参数实质是指向被装饰函数的内存地址

:return:"""

def inner(*args, **kwargs):"""该函数为装饰器函数内部函数

:param args: 实质接收的是被装饰函数的位置参数

:param kwargs: 实质接收的是被装饰函数的关键字参数

:return: 返回的是被装饰函数的返回值"""

print("这里放被装饰函数执行之前要做的事")

func_ret= func(*args, **kwargs) #被装饰的函数

print("这里放被装饰函数执行之后要做的事")returnfunc_retreturninner

@wrapper#等价于my_func = wrapper(my_func)

def my_func(*args, **kwargs):"""该函数为被装饰函数

:param args: 接收位置参数

:param kwargs: 接收关键字参数

:return: 返回值"""

print(*args, **kwargs)returnret

ret= my_func() #执行原函数,实质是执行inner()。函数返回值保存在变量ret中。

6、装饰器修复

当我们使用装饰器去装饰某个函数时,我们想要引用被装饰函数原私有属性,如__name__、__doc__时,就有问题了,因为我们虽然仍然在执行被装饰函数,但其实执行的是闭包,看下例。

defwrapper(func):"""该函数为装饰器函数

:param func: 这里的func参数实质是指向被装饰函数的内存地址

:return:"""

def inner(*args, **kwargs):"""该函数为闭包(装饰器函数内部函数)

:param args: 实质接收的是被装饰函数的位置参数

:param kwargs: 实质接收的是被装饰函数的关键字参数

:return: 返回的是被装饰函数的返回值"""func_ret= func(*args, **kwargs) #被装饰的函数

returnfunc_retreturninner

@wrapper#等价于my_func = wrapper(my_func)

def my_func(*args, **kwargs):"""该函数为被装饰函数

:param args: 接收位置参数

:param kwargs: 接收关键字参数

:return: 返回值"""

print(*args, **kwargs)return "返回值"my_func("装饰器没被修复前,被装饰函数原函数的私有属性如__name__、__doc__是获取不到的,如下:") #执行原函数,实质是执行inner()

print(my_func.__name__) #打印函数的名字

print(my_func.__doc__) #打印函数的注释文档

输出结果如下:

如果仍想使用被装饰函数的原私有属性,那么就可以用装饰器修复:

from functools importwrapsdefwrapper(func):"""该函数为装饰器函数

:param func: 这里的func参数实质是指向被装饰函数的内存地址

:return:"""@wraps(func)def inner(*args, **kwargs):"""该函数为闭包(装饰器函数内部函数)

:param args: 实质接收的是被装饰函数的位置参数

:param kwargs: 实质接收的是被装饰函数的关键字参数

:return: 返回的是被装饰函数的返回值"""func_ret= func(*args, **kwargs) #被装饰的函数

print("装饰器修复不会改变原装饰器的作用")returnfunc_retreturninner

@wrapper#等价于my_func = wrapper(my_func)

def my_func(*args, **kwargs):"""该函数为被装饰函数

:param args: 接收位置参数

:param kwargs: 接收关键字参数

:return: 返回值"""

print(*args, **kwargs)return "返回值"my_func("装饰器被修复后,被装饰函数原函数的私有属性如__name__、__doc__就可以正常获取了,如下:") #执行原函数,实质是执行inner()

print(my_func.__name__) #打印函数的名字

print(my_func.__doc__) #打印函数的注释文档

输出结果如下:

7、带参数的装饰器

需求:很多函数共用一个装饰器,要求随时可以关闭装饰器功能,且尽可能的减少代码修改。 该需求可以用标记位来实现,如下:

importtime

FLAG=Truedeftimmer_out(flag):deftimmer(func):def inner(*args, **kwargs):ifflag:

start_time=time.time()

ret_func= func(*args, **kwargs)

end_time=time.time()

used_time= end_time -start_timeprint("函数{name}执行时间:{time}".format(name=func.__name__, time=used_time))#print("函数{name}执行时间:{time}".format_map({"name": func.__name__, "time": used_time}))

else:

ret_func= func(*args, **kwargs)returnret_funcreturninnerreturntimmer

@timmer_out(FLAG)#第一步,先执行timmer_out(FLAG),得到返回值timmer。第二步执行@timmer,即 my_func1 = timmer(my_func1)

defmy_func1():

time.sleep(1)print("my_func1")

@timmer_out(FLAG)defmy_func2():

time.sleep(1)print("my_func2")

@timmer_out(FLAG)defmy_func3():

time.sleep(1)print("my_func3")

my_func1()

my_func2()

my_func3()

当FLAG置为True时,装饰器功能生效,输出结果如下图所示:

当FLAG置为False时,装饰器功能关闭,输出结果如下图所示:

8、多个装饰器装饰一个函数

defwrapper1(func):definner1():print("wrapper1, before func")

func()print("wrapper1, after func")returninner1defwrapper2(func):definner2():print("wrapper2, before func")

func()print("wrapper2, after func")returninner2

@wrapper2

@wrapper1defmy_func():print("function is my func")

my_func()

注意输出结果:

为什么结果是这样?请看如下分析:

为什么是先执行@wrapper1而不是@wrapeer2呢?因为装饰器在找到被装饰函数会优先执行。

python装饰器源代码_13-Python-装饰器相关推荐

  1. 在当当买了python怎么下载源代码-初学Python 之抓取当当网图书页面目录并保存到txt文件...

    这学期新开了门"高大上"的课<机器学习>,也开始入门Python.然后跟我们一样初学Python 的老师布置了个"作业"--用Python 弄个抓取 ...

  2. python飞机大战源代码-制作python程序windows安装包(飞机大战源码)

    本文以飞机大战源码为例: 1.首先使用pyinstaller -w xxx.py打包 -w的意思是不显示命令行:飞机大战源码由多个.py文件以及一些图片,音乐文件组成,我们将main.py打包, 其他 ...

  3. Python网上商城源代码,基于Django+MySQL+Redis,支持支付宝付款

    Python网上商城源代码,基于Django+MySQL+Redis,支持支付宝付款,实现:用户登录注册,商品展示,商品详情界面,搜索商品,将不同尺寸颜色数量的商品加入购物车,购物车管理,地址管理,形 ...

  4. Python足球游戏源代码,热血足球小游戏,可双人玩

    基于Python pygame的足球游戏源代码,游戏可以双人玩,游戏入口程序为soccer.py. 控制人物一 方向键:wasd ,射门键:r 控制人物二,方向键: 键盘方向键,射门键:k 程序运行截 ...

  5. Python版记事本源代码

    Python版记事本源代码,程序运行截图: import tkinter as tk import tkinter.scrolledtext as tkst import fileinput from ...

  6. Python基础15-函数闭包与装饰器

    目录 装饰器概念 装饰器的实现 修改被装饰函数的代码(非装饰器实现) 修改被装饰函数的调用方式(非装饰器实现) 装饰器的实现(不完整的实现level1) 装饰器实现的语法糖(不完整的实现level2) ...

  7. python类装饰器详解-Python 装饰器详解

    开放封闭原则: 开放对扩展 封闭修改源代码 改变了人家调用方式 装饰器结构 """ 默认结构为三层!!!每层返回下一层内存地址就可以进行执行函数, 传参:语法糖中的传参可 ...

  8. 在Python中的无参装饰器和有参装饰器

    装饰器特点: 1.开放封闭原则,即对扩展是开放的,对修改时封闭的: 2.装饰器本质可以是任意可调用的对象,被装饰的对象也可以是任意可调用对象: 3.装饰器的功能是在不修改被装饰器对象源代码以及被装饰器 ...

  9. python四大高阶函数_详谈Python高阶函数与函数装饰器(推荐)

    一.上节回顾 Python2与Python3字符编码问题,不管你是初学者还是已经对Python的项目了如指掌了,都会犯一些编码上面的错误.我在这里简单归纳Python3和Python2各自的区别. 首 ...

最新文章

  1. 国内能打自动驾驶出租车了!行驶平稳还免费,首个量产车型开放道路试运营...
  2. React Native 的顶部导航栏和底部导航栏目
  3. 哈夫曼编码的非树节点形式实现
  4. 九个PHP很有用的功能
  5. ubuntu在 hdfs上创建一个文件夹_NAS上如何创建和使用加密文件夹?
  6. 怎么看笔记本电脑的配置参数_想给笔记本电脑硬件配置升级,我应该怎么升?...
  7. python里none什么意思_Python 中None的用法
  8. [Android] Android开机启动Activity或者Service方法
  9. 关于用户登录的记住密码实现思路(考虑到安全问题)
  10. 广州地铁的速度与激情
  11. 【精选】抽奖点名、随机抽奖PPT素材合集,年会、老师必备
  12. 车联网技术与产业发展趋势 学习记录
  13. winxp+win7蓝屏代码
  14. ICPC Greater New York Region 2020 L Evenly Separated Strings
  15. steam饥荒存档备份_如何手动备份您的Steam游戏文件
  16. 什么无线耳机音质最好,无线耳机品牌排行榜
  17. 利用requests库下载视频
  18. RISC-V架构中断定义
  19. Ubuntu Mint Installation Guide
  20. 又火了一本神书,看小说就能学 JavaScript?

热门文章

  1. Visual Studio现可使用EditorConfig
  2. 2016.NET Core相关内容回顾
  3. php 随机指定位数,php生成一个可选位数的随机码
  4. java中的path类_详谈java中File类getPath()、getAbsolutePath()、getCanonical的区别
  5. XunSearch的安装和加入服务器开机脚本以及将目录写入系统变量
  6. C#数组原来这么简单,你学废了吗?
  7. Android之可伸缩的皮筋效果(贝塞尔曲线)的介绍
  8. sklearn 线性回归_使用sklearn库做线性回归拟合
  9. c++ 对象起始地址 指针靠齐_你需要知道的各种指针运算
  10. wms地图绘制工具_移情地图,了解用户需求的利器