热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python“三大器”之装饰器1

一、装饰器1、什么是装饰器?装饰:装饰、修饰器:工具装饰器:装饰的工具(*****)“开放封闭”:装饰器必须要

一、装饰器


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中的smtplib库来发送带有附件的邮件,并提供了完整的代码示例。作者:多测师_王sir,时间:2020年5月20日 17:24,微信:15367499889,公司:上海多测师信息有限公司。 ... [详细]
  • python模块之正则
    re模块可以读懂你写的正则表达式根据你写的表达式去执行任务用re去操作正则正则表达式使用一些规则来检测一些字符串是否符合个人要求,从一段字符串中找到符合要求的内容。在 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • Python 序列图分割与可视化编程入门教程
    本文介绍了如何使用 Python 进行序列图的快速分割与可视化。通过一个实际案例,详细展示了从需求分析到代码实现的全过程。具体包括如何读取序列图数据、应用分割算法以及利用可视化库生成直观的图表,帮助非编程背景的用户也能轻松上手。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • 自然语言处理(NLP)——LDA模型:对电商购物评论进行情感分析
    目录一、2020数学建模美赛C题简介需求评价内容提供数据二、解题思路三、LDA简介四、代码实现1.数据预处理1.1剔除无用信息1.1.1剔除掉不需要的列1.1.2找出无效评论并剔除 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 利用python爬取豆瓣电影Top250的相关信息,包括电影详情链接,图片链接,影片中文名,影片外国名,评分,评价数,概况,导演,主演,年份,地区,类别这12项内容,然后将爬取的信息写入Exce ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 本文介绍了如何使用Python的Paramiko库批量更新多台服务器的登录密码。通过示例代码展示了具体实现方法,确保了操作的高效性和安全性。Paramiko库提供了强大的SSH2协议支持,使得远程服务器管理变得更加便捷。此外,文章还详细说明了代码的各个部分,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • 本文详细探讨了使用Python3编写爬虫时如何应对网站的反爬虫机制,通过实例讲解了如何模拟浏览器访问,帮助读者更好地理解和应用相关技术。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
author-avatar
淇蒴_192
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有