一、装饰器

1、什么是装饰器?

  装饰:装饰、修饰

  器:工具

  装饰器:装饰的工具

  (*****)“开放封闭”:装饰器必须要遵循“开放封闭”原则:

    开放:对函数功能的添加是开放的

    封闭:对函数功能的修改是封闭的

2、装饰器的作用?

  在不修改被装饰对象源代码与调用方式的前提下添加新的功能。

  装饰器必须遵循的两个原则:

    不修改被装饰对象源代码

    不修改被装饰对象的调用方式

ps:

  被装饰对象指的是  --->  需要添加功能的(函数)

  装饰器指的是  --->  被装饰对象添加的新功能的(函数)

3、为什么要使用装饰器?

  可以解决代码荣誉问题,提高代码的可扩展性

4、怎么使用装饰器?

  编写装饰器:

    通过闭包函数来实现装饰器

  装饰器的应用:

    1、统计时间

    2、登录认证

例子:

  需求:需要统计一下下载电影的时间

    方案一:函数调用(适合少次使用)

import timedef download_movie():print("开始下载电影...")# 模拟电影下载时间为3秒time.sleep(3)print("电影下载成功!")start_time = time.time()    # 获取当前时间戳
download_movie()
end_time = time.time()    # 获取当前时间戳
print(f"消耗时间:{end_time - start_time}")

  问题1:如果有多个被装饰对象,需要写多次统计时间的代码,导致代码冗余,于是有了方案二。

    方案二:使用装饰器(适合多次调用,调用时直接在闭包函数内传入所需要使用装饰器的函数名称)

import timedef download_movie():print("开始下载电影...")# 模拟电影下载时间为3秒time.sleep(3)print("电影下载成功!")# 模拟多个被装饰对象
def func1():pass# 模拟多个被装饰对象
def func2():pass# 装饰器:初级版
def time_record(func):def inner():# 获取当前时间戳start_time = time.time()func()# 获取当前时间戳end_time = time.time()print(f"消耗时间:{end_time - start_time}")return innerdownload_movie = time_record(download_movie)
download_movie()

  问题2:如果被装饰对象有返回值,有参数而且有多个参数,于是有了方案三。

    方案三:方案二的代码优化,使用*args, **kwargs接收所有参数(形参,关键字参数等)import time

def download_movie(*args, **kwargs):print("开始下载电影...")# 模拟电影下载时间time.sleep(3)print("电影下载成功!")return "movie.mp4"# 装饰器最终版
def time_record(func):def inner(*args, **kwargs):    # *args **kwargs接收所有参数(形参,关键字参数等)# 获取当前时间戳start_time = time.time()# 将被装饰对象需要接收的人以参数,原封不动的传给func(被修饰对象)res = func(*args, **kwargs)    #此处的fanc为被修饰对象download_movie()# 获取当前时间戳end_time = time.time()# 统计结束,打印统计时间print(f"消耗时间:{end_time - start_time}")return resreturn inner# 这里的download_movie是inner()的返回值
download_movie = time_record(download_movie)
# download_movie()  --->  inner() ,可传入任意参数,若传入参数,download_movie()函数需要修改代码块,否则不打印或者不执行传入参数
download_movie()

  方案三完美的解决了方案一和方案二遗留下的问题,此处的装饰器可以作为所有装饰器的模板

  (*****)装饰器模板(记牢)

def wrapper(func):def inner(*args, **kwargs):    # *args **kwargs接收所有参数(形参,关键字参数等)# 调用被装饰对象,得到被装饰对象的返回值resres = func(*args, **kwargs)return resreturn inner

  装饰器简例:

def wrapper(func):def inner(*args, **kwargs):'''在此处可以添加新添加的功能代码块'''# 调用被装饰对象,得到被装饰对象的返回值resres = func(*args, **kwargs)'''在此处也可以添加新添加的功能代码块'''return resreturn innerdef func1():print("hello")func1 = wrapper(func1)
func1()

代码执行顺序:

  def为定义函数,不执行

  先执行同级代码,再执行下级函数体代码

回到顶部

二、装饰器语法糖

  装饰器的语法糖,是属于装饰器的(语法糖是装饰器内置的,可以引用所有的语法糖)

  @装饰器名字      装饰器的语法糖

  注意:在使用装饰器语法糖时,装饰器必须定义在被装饰对象之上

例子:统计函数执行时间

  不使用装饰器语法糖:

import time# func函数执行三秒
def func():time.sleep(3)# 装饰器:统计函数执行时间
def wrapper(func):    # func被装饰对象def inner(*args, **kwargs):    # *args, **kwargs是被装饰对象的参数# 调用前增加新功能start_time = time.time()res = func(*args, **kwargs)# 调用前增加新功能end_time = time.time()print(f"程序执行时间为:{end_time - start_time}秒")return res    # 调用被装饰对象,接收返回值return inner# 不使用装饰器语法糖
func = wrapper(func)
func()

  使用装饰器语法糖:

import time# 装饰器:统计函数执行时间
def wrapper(func):    # func被装饰对象def inner(*args, **kwargs):    # *args, **kwargs是被装饰对象的参数# 调用前增加新功能start_time = time.time()res = func(*args, **kwargs)# 调用前增加新功能end_time = time.time()print(f"程序执行时间为:{end_time - start_time}秒")return res    # 调用被装饰对象,接收返回值return inner# 使用装饰器语法糖:使用装饰器语法糖时,装饰器必须定义在被装饰对象之上
@wrapper    # @wrapper    就等于--->   func = wrapper(func)
# func函数执行三秒
def func():time.sleep(3)func()    # 因为语法糖可直接调用

回到顶部

三、装饰器练习题

  编写一个装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名密码

  可写完对照

# 定义一个字典来做判断
user_info = {"user" : None,    # username与user_info["user"]来判断是否已登录用户
}# 登录功能:
def login():# 判断用户没有登录时,执行# 登陆功能print("请先登录")username = input("请输入你的用户名:").strip()password = input("请输入您的密码:").strip()# 打开密码表,对比账户密码是否正确with open("dir/passwd.txt", "r", encoding="utf-8") as f:for line in f:# print(line)name, pwd = line.strip("\n").split(":")  # 得到[tank, 123]if username == name and password == pwd:print("登陆成功!")user_info["user"] = usernameelse:print("登录失败")# 登录认证装饰器:
def login_auth(func):def inner(*args, **kwargs):# 登录认证功能# 如果已经登录,将被装饰对象直接调用并返回if user_info.get("user"):res = func(*args, **kwargs)return res# 如果没有登录,执行登录功能else:login()    # 调用login()函数进行登录return inner# func1、2、3都需要先登录才能使用,若登陆一次,后续就不需要再次登录
# 登陆之后可以使用的功能1
@login_auth
def func1():print("from func1")pass# 登陆之后可以使用的功能2
@login_auth
def func2():print("from func2")pass# 登陆之后可以使用的功能3
@login_auth
def func3():print("from func3")pass# 执行环节
while True:func1()input("延迟操作")func2()func3()

本文首发于python黑洞网,csdn同步更新

Python“三大器”之装饰器1相关推荐

  1. 自学Python第五天。Python 三大器

    今天是自学Python的第五天了.今天主要学习了Python的三大器.装饰器,迭代器,生成器 #装饰器:可以在不改变代码的基础上,给函数添加新的功能. # 可以在原有操作前面或者后面随意的添加新的功能 ...

  2. python三大器_Python - 三大器 迭代器,生层器,装饰器

    Python - 三大器 迭代器,生层器,装饰器 在介绍三大器之前先来了解一下容器和可迭代对象... 一. 容器 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, ...

  3. python 三大器

    python 三大器 迭代器: 有__iter__()和__next__()方法 生成器:函数中将return换成yield 装饰器:闭包的本质 迭代器 ''' 遇到问题没人解答?小编创建了一个Pyt ...

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

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

  5. 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解

    第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一.    引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...

  6. itext生成pdf paragraph 自动换行_reportlab高级制作多格式PDF和python的class和装饰器复习

    1 说明 1.1 reportlab高级制作多格式PDF:即包含文字.表格.柱状图. 1.2 复习python的class和装饰器的高级基础知识. 1.3 列表转换字符串.读取txt文件等python ...

  7. python return用法_初学Python要了解什么 装饰器知识汇总有哪些

    初学Python要了解什么?装饰器知识汇总有哪些?在Python学习过程中,有多种方法对函数和类进行加工,相对于其它方式,装饰器语法简单,代码可读性高.因此,装饰器在Python项目中有广泛的应用,比 ...

  8. python装饰器传递参数_Python装饰器高级版—Python类内定义装饰器并传递self参数...

    本文重点:解决了类里面定义的装饰器,在同一个类里面使用的问题,并实现了装饰器的类属性参数传递 目录: 一.基本装饰器 二.在类里定义装饰器,装饰本类内函数 三.类装饰器 正文: 一.基本装饰器 装饰不 ...

  9. python log函数_python装饰器的使用

    1. 装饰者模式 装饰者模式是常用的软件设计模式之一.通过此设计模式,我们能够在不修改任何底层代码情况下,给已有对象赋予新的职责.python中可以用装饰器简单地实现装饰者模式. 1.1 将函数作为参 ...

最新文章

  1. 新MGDN论坛重新恢复
  2. 嵌入式jetty --- 转载
  3. Nginx配置Basic Auth登录认证的实现方法
  4. An error has occurred while drawing:java.lang.IllegalStateException: The display list is not valid.
  5. C#中5步完成word文档打印的方法
  6. 【转】Jmeter + DadBoby 安装使用
  7. ABB机器人VGT文件_ABB机器人与焊机之间通讯方式
  8. 装饰者模式 php,php装饰者模式简单应用案例分析
  9. Axure Rp8激活码
  10. 飞鸽传书软件局域网传输文件
  11. 戴尔服务器进入pxe启动
  12. 文言文编程可以编译成PHP吗,PSTK项目:文言文也能编程?大四学生发明文言文编程语言...
  13. 【python学习.油价和美元汇率查询】
  14. 5.表达式求值(1)
  15. mysql表中字段数据类型_mysql数据表中字段的数据类型有哪些?
  16. 假如小明今年第1季度的三个月中的营业额分别是{5,10,15},第二季度他计划要把第1季度中每个月的营业额都提升为2倍,请你帮小明同学计算出他第二季度的每个月营业额;
  17. python基础练习题(一)
  18. ReactJS 傻瓜教程
  19. 腾讯qq珊瑚虫版_腾讯QQ迎来重大更新:三大新功能上线,短板补齐了
  20. 408数据结构(王道版+邓俊辉版)

热门文章

  1. 分享经验,让更多的人受益
  2. android 栈溢出 检查,安卓源码编译完成后打包时出现栈溢出,求大家解决
  3. mysql amoeba 链接111,mycat1.4 amoeba3.0.5 mysql直连对照_mysql
  4. CPU是如何处理指令的
  5. hadoop之DataBlockScanner
  6. MySQL step by step 安装实战
  7. (22)Xilinx FPGA PCIE中断接口(学无止境)
  8. (139)FPGA面试题-FPGA设计中的速度和面积互换原则
  9. (20)FPGA面试题时序设计的实质
  10. 大学计算机网络实验2,河南工业大学计算机网络实验报告2