Python之装饰器的使用

目录

  • 闭包
  • 装饰器
      • 函数实现
      • 原理
      • 类实现(带参数)
      • 装饰类
      • 应用
        • 权限控制
        • 计时和添加日志
        • 系统识别
        • redis_require
  • 小结


闭包

对于函数内声明的变量一般都为临时变量,其生命周期随函数结束而结束。

但闭包是个例外

闭包满足的条件:
1、必须要有内嵌函数
2、内函数必须引用外函数的变量
3、外函数必须返回的内函数

def outer(x):a = 300def inner():print(x+a)return inner	# 这里不能打括号,不然就是返回调用了
d = outer(100)
d()		# 输出400

对于闭包函数对象,其内置属性__closure__非空

print(d.__closure__)	# 会记录其引用了的变量
(<cell at 0x00000256060C2FD0: int object at 0x0000025604DB7F70>, <cell at 0x00000256060C2FA0: int object at 0x00000256757955D0>)

装饰器

装饰器本质就是闭包函数,需要把一个callable(函数、类)对象作为参数传入进去,所以装饰器只能用在函数或类上面

装饰器是一种设计模式,主要用于在不改变函数或者类的源代码的基础上,给其添加一些额外的功能

装饰器并非python独有,只要能实现闭包的语言都能实现装饰器

函数实现

# 装饰器模板,在此基础上添加新功能
def runtime(func):def inner(*args,**kwargs):		# 这样可以接收任意个参数result = func(*args,**kwargs)return resultreturn inner
# 装饰器,用于统计函数执行时间
def runtime(func):def inner(*args,**kwargs):start = time.time()result = func(*args,**kwargs)end = time.time()print(f"执行{func.__name__}花费{end-start}s")return resultreturn inner@runtime		# 给函数应用装饰器,去掉该装饰语句后就不会执行装饰器的效果;	func1 = runtime(func1)
def func1():time.sleep(2)print("func1")func1()			# 调用的时候没有任何区别,无需改变源代码,然实际调用的是inner()函数
#---输出---
func1
执行func1花费2.012355089187622s

原理

当代码执行到@runtime时,runtime函数就已经被执行(func1函数也被传入到runtime函数中)

此时调用func1函数时,实际调用为inner()函数,证据是print(func1.__name__)为inner

类实现(带参数)

函数实现想带参数也只需在定义时声明和装饰时传入就好

class A:def __init__(self, username):	# 通过init函数传参self.username=usernamedef __call__(self, func):		# 通过call函数进行实现装饰器def inner(*args,**kwargs):result = func(*args,**kwargs)return resultreturn inner@A(username="root")		# 通过类进行装饰和传参
def func1():pass

装饰类

def runtime(cls):def inner(*args,**kwargs):		# 装饰器函数返回的就是类了,而不是返回值return cls(*args,**kwargs)return inner@runtime
class A:passa1 = A()	# 与装饰函数一样,此时A调用的cls这个内部函数

应用

  • 引入日志,用于1.排错、分析和定位故障;2.用户行为分析;3.页面埋点(相当于数据采集)
  • 增加计时逻辑来检测性能
  • 给函数加入事务的能力
  • 权限控制
  • ……

权限控制

# 权限控制
username = input("输入你的用户名:")def login_require(func):def inner(*args,**kwargs):if username != "root":		# 当用户为root时才能执行add函数print("权限拒绝!")returnresult = func(*args,**kwargs)return resultreturn inner@login_require
def add(x,y):print(x+y)add(1,2)

计时和添加日志

# 对add函数添加两个装饰器,一个记录花费时间,一个添加日志
import time
def run_time(func):def inner(*args,**kwargs):start_time=time.time()result = func(*args,**kwargs)end_time = time.time()print(f"{func.__name__}程序运行共花费{end_time-start_time}s")return resultreturn innerimport logging
def log_add(func):def inner(*args,**kwargs):LOG_FORMAT = "%(asctime)s - %(filename)s[%(levelname)s] : %(message)s"logging.basicConfig(format=LOG_FORMAT)logging.warning(f"-->{func.__name__}<--程序被执行!")result = func(*args,**kwargs)return resultreturn inner@run_time
@log_add
def add(x,y):return x+yresult = add(1,2)
print(result)# 输出效果
inner程序运行共花费0.0009965896606445312s
2023-08-25 11:43:02,963 - 装饰器练习.py[WARNING] : -->add<--函数被执行!
3

系统识别

# 写一个局域网扫描函数,--subprocess,再写一个装饰器,判断当前系统是否为linux,是才能执行# 实现ping函数,ping成功返回true,否则为false
import platform    # For getting the operating system name
import subprocess  # For executing a shell commanddef require_linux(func):def inner(*args,**kwargs):if platform.system().lower() == 'linux':return func(*args,**kwargs)else:print(f"操作系统不是linux,拒绝执行{func.__name__}!")returnreturn innerdef ping(host):"""Returns True if host (str) responds to a ping request.Remember that a host may not respond to a ping (ICMP) request even if the host name is valid."""# Option for the number of packets as a function ofparam = '-n' if platform.system().lower()=='windows' else '-c'# Building the command. Ex: "ping -c 1 google.com"command = ['ping', param, '1', host]return subprocess.call(command) == 0@require_linux
def scan_lan(net_segment):list = net_segment.split('.')seg = '.'.join(list[0:3])for i in range(1,255):host = seg + "." + str(i)if ping(host):with open("actived.txt",'a') as fp:		# 将能到达的服务器ip写入文件fp.write(f"{host}\n")else:with open("unreachable.txt",'a') as fp:fp.write(f"{host}\n")returnscan_lan(net_segmeng)# --------效果--------
# Windows:
C:\Users\zhihe>python3 D:\pycharm2020.3\My_Project\装饰器.py
操作系统不是linux,拒绝执行scan_lan!
# Linux:
[root@zh-ali py练习]# tail unreachable.txt
172.26.252.1
172.26.252.2
172.26.252.3
……

redis_require

写一个装饰器,对于要查询的同学信息,在给定同学id后先到redis上查找,查找不到再去mysql查找,并将查找到的值写入到redis。

import redis
import pymysql'''
对于要查询的同学信息,在给定同学id后先到redis上查找,查找不到再去mysql查找,并将查找到的值写入到redis。
'''def redis_req(func):def inner(id):r = redis.Redis(host='192.168.10.21', port=6379, db=1, decode_responses=True)if r.hkeys(id):print("通过redis查询:")print(f"同学姓名:{r.hget(id, 'name')}")print(f"同学年龄:{r.hget(id, 'age')}")print(f"同学成绩:{r.hget(id, 'grade')}")data = (int(id),r.hget(id, 'name'),int(r.hget(id, 'age')),int(r.hget(id, 'grade')))	# 保证data格式与mysql返回格式一致else:data = func(id)print("通过mysql查询:")if data:				# data不为空时才输出并写入到redisprint(data)r.hset(id, "name", data[1])r.hset(id, "age", data[2])r.hset(id, "grade", data[3])else:print("该id不存在!")r.close()return datareturn inner@redis_req
def mysql(id):db = pymysql.connect(host='192.168.10.21',# port=3306,user='zh',password='123456',database='zh')cursor = db.cursor()cursor.execute(f"select * from stu where id={id}")data = cursor.fetchone()db.close()return dataid = input("输入你要查询的同学id:")
data = mysql(id)
print(data)

小结

本节文章讲解了什么是闭包、装饰器的函数和类实现以及几个实用的装饰器例子,希望能帮助大家快速理解并上手,有什么问题欢迎留言,我会及时回复,感谢观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/83113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记|外部中断|INT0|中断列表|STC32G单片机视频开发教程(冲哥)|第十五集:中断系统和外部中断

文章目录 1.中断和中断系统1.1什么是中断?1.2什么是中断系统1.3中断系统的优点1.4 中断系统包含哪些中断源1.5.中断次序 2.什么是外部中断3.外部中断的用法4.外部中断的用法新的测试场景完整代码 总结课后练习: 上节课我们学完了GPIO的矩阵按键&#xff0c;已经把这个GPIO的一…

视频讲解|1033含sop的配电网重构(含风光可多时段拓展)

目录 1 主要内容 程序特点 讲解重点 2 视频链接 1 主要内容 该视频为含sop的配电网重构matlab代码讲解&#xff0c;对应资源下载链接为含sop的配电网重构&#xff08;含风光|可多时段拓展&#xff09;&#xff0c;程序主要内容是&#xff1a;针对含sop的配电网重构模型&…

基于Java的公务员考试资料共享平台的设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

LuatOS-SOC接口文档(air780E)--dac - 数模转换

dac.open(ch, freq, mode) 打开DAC通道,并配置参数 参数 传入值类型 解释 int 通道编号,例如0 int 输出频率,单位hz int 模式,默认为0,预留 返回值 返回值类型 解释 true 成功返回true,否则返回false int 底层返回值,调试用 例子 if dac.open(0, 44000) the…

【Linux基础】第28讲 Linux Vi编辑器

在Linux下一班使用Vi编辑器来编辑文件vi既可以查看文件也可以编辑文件而vim是vi的升级版本&#xff0c;具备更多的功能。vi如果目标文件不存在&#xff0c;会创建新的文件。但如果新文件没做编辑&#xff0c;退出后还会消失。 VI的三种模式介绍 三种模式&#xff08;状态&…

emacs从缓冲中获取信息,并执行shell 命令

/* author: hjjdebug * date : 2023年 09月 20日 星期三 11:39:11 CST * description: emacs从缓冲中获取信息,并执行shell 命令 */ 我有一个udp频道的列表,如下: 239.3.1.105:8092 | IP 61.135.101.121.8046 > 239.3.1.124:8128 | IP 61.135.101.118.8050 >…

[golang 流媒体在线直播系统] 2.搭建基于golang的流媒体服务器实现拉流推流,以及Html客户端拉取hls类型的流

一.使用 Go 语言的开源框架Livego搭建流媒体服务器 1.Livego 框架的介绍 Go 语言拥有强大的 服务器性能 ,golang 在语言级别解决了 多进程并发 的问题,支持 多核 CPU均衡使用 ,支持 海量轻量级线程 ,所以非常适合做 流媒体服务器 .而 livego 是基于golang 开发的简单高效的…

UML基础与应用之面向对象

UML&#xff08;Unified Modeling Language&#xff09;是一种用于软件系统建模的标准化语言&#xff0c;它使用图形符号和文本来描述软件系统的结构、行为和交互。在面向对象编程中&#xff0c;UML被广泛应用于软件系统的设计和分析阶段。本文将总结UML基础与应用之面向对象的…

uniapp 拉起微信支付方法封装

本文示例基于 uniapp 的 uni.requestPayment() 微信支付拉起方法封装及调用示例&#xff1a; 方法封装 注&#xff1a;方法为 vue3 hooks 写法 可直接复制使用&#xff0c;但要注意传入的 data 参数中的各字段名&#xff0c;结合各自拉起支付时后端返回的参数字段做相应修改。…

程序员的文案

目录 这个社会的规则或者真相&#xff0c;跟人情一毛钱关系都没有 心平能愈三千疾&#xff08;无欲无求是完人&#xff09; 永远不要做羞耻心太重的人&#xff08;丢人是成长最快的方式&#xff09; 好脾气留给最亲的人 这个社会的规则或者真相&#xff0c;跟人情一毛钱关系…

网络爬虫-----爬虫的分类及原理

目录 爬虫的分类 1.通用网络爬虫&#xff1a;搜索引擎的爬虫 2.聚焦网络爬虫&#xff1a;针对特定网页的爬虫 3.增量式网络爬虫 4.深层网络爬虫 通用爬虫与聚焦爬虫的原理 通用爬虫&#xff1a; 聚焦爬虫&#xff1a; 爬虫的分类 网络爬虫按照系统结构和实现技术&#…

Linux——IO

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;Linux——文件系统 ☂️<3>开发环境&#xff1a;Centos7 &#x1f4ac;<4>前言&#xff1a;是不是只有C/C有文件操作呢&#xff1f;python&#xff0c;java&…

长尾关键词挖掘软件-免费的百度搜索关键词挖掘

嗨&#xff0c;大家好&#xff01;今天&#xff0c;我想和大家聊一聊长尾关键词挖掘工具。作为一个在网络世界里摸爬滚打多年的人&#xff0c;我对这个话题有着一些个人的感悟和见解&#xff0c;希望能与大家分享。 首先&#xff0c;让我坦白一点&#xff0c;长尾关键词挖掘工具…

《计算机视觉中的多视图几何》笔记(3)

3 Projective Geometry and Transformations of 3D 这章主要讲的是3D的射影几何&#xff0c;与2D的射影几何差不多。主要区别是&#xff1a; 3D射影几何对偶的是点和平面&#xff0c;直线是自对偶的。3D空间中直线有4个自由度&#xff0c;这一现象并不是那么容易直接得出。一…

SBCS、DBCS、ASCII、MBCS(ANSI)、Unicode

1.三种编码方式和三种字符类型。 第一种编码方式是单字节字符集&#xff0c;称之为 SBCS&#xff0c;它的所有字符可用一个字节存储。ASCII 码就是SBCS。SBCS字符串由一个零字节结尾。第二种编码方式是多字节字符集&#xff0c;称之为 MBCS&#xff0c;它包含的字符中有单字节…

实现注册手机号用户

1、使用Post异步发送请求&#xff08;发送短信&#xff09;&#xff0c;离焦事件触发时判断 <script src"layer/layer.js"></script><!--离焦事件--><script type"text/javascript" th:inline"javascript">$("#use…

HCS 基本概念(三)

一、定义 HCS采用FusionSphere OpenStack作为云平台&#xff0c;对各个物理数据中心资源做整合&#xff0c;采用ManageOne作为数据中心管理软件对多个数据中心提供统一管理&#xff0c;通过云平台和数据中心管理软件协同运作&#xff0c;达到多数据中心融合、提升企业整体IT效率…

2023最新安装微信小程序开发软件安装教程

一&#xff0c;安装开发者工具 我们在开发小程序之前&#xff0c;首先需要安装小程序开发者工具&#xff0c;今天就来教大家安装小程序开发者工具。 微信开放文档 (qq.com)https://developers.weixin.qq.com/miniprogram/dev/framework/ 官网工具下载地址&#xff1a; 微信…

在windows下持续ping ip,将返回结果及时间记录到文件中

在纯英文路径下创建文件ping.txt 在txt中写入 Dim args, flag, unsuccOut args"" otherout"" flag0If WScript.Arguments.count 0 Then WScript.Echo "Usage: cscript tping.vbs [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]" WScr…

NDK (ndk)报错 Unity requires NDK r19 (64-bit)(19.0.05232133)

一、介绍 在 Android 添加 NDK ndk 的时候&#xff0c;出现 Unity requires NDK r19 (64-bit)(19.0.05232133)。 二、环境 1、Unity 2020.3.48f1c1 2、Android NDK 配置 三、报错信息 NDK (ndk)报错 Unity requires NDK r19 (64-bit)(19.0.05232133) 四、解决方法 1、下…