python基础之装饰器详解
作者:思想流浪者 发布时间:2022-05-22 15:26:38
标签:python,装饰器
一、前言
装饰器:本质就是函数,功能是为其他函数添加附加功能
原则:
1、不修改被修饰函数的源代码
2、不修改被修饰函数的调用方式
装饰器 = 高阶函数 + 函数嵌套 + 闭包
二、高阶函数
高阶函数定义:
1、函数接收的参数是一个函数
2、函数的返回值是一个函数名
3、满足上述条件任意一个,都可以称为高阶函数
test 函数是高阶函数,接受了一个foo 作为参数
import time
def foo():
time.sleep(3)
print("sleep 3s")
def test(func):
start_time = time.time()
func()
stop_time = time.time()
print("函数的运行时间是: %s" % (stop_time - start_time))
test(foo)
timer 是一个高阶函数,这个函数返回值是一个函数
import time
def foo():
time.sleep(3)
print("sleep 3s")
def timer(func):
start_time = time.time()
func()
stop_time = time.time()
print("执行时间{}".format(stop_time - start_time))
return func
foo = timer(foo)
foo()
# 结果: 多运行了一次
三、函数嵌套
在函数里面定义函数,变量的作用域和生存周期不变。
def father(name):
print("father name: %s" % name)
def son():
print("son name: %s" % name)
son()
father("xu1")
# 结果:
# father name: xu1
# son name: xu1
四、装饰器
实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打印
import time
def timer(func): # 实现一个计算函数执行时间的函数作为装饰器,用来计算被装饰函数的执行时间并打出
def wrapper():
start_time = time.time()
func()
stop_time = time.time()
print("运行时间: %s" % (stop_time - start_time))
return wrapper
# def test(): # 不使用装饰器的同等实现
# time.sleep(3)
# print("test sleep 3s")
#
# test = timer(test) # 返回的是 wrapper 的地址
# test() # 执行的是 wrapper
@timer
def test(): # 装饰器的实现
time.sleep(3)
print("test sleep 3s")
test() # 执行的是 wrapper
# 结果:
# test sleep 3s
# 运行时间: 3.000915050506592
4.1 被装饰方法带返回值
import time
def timer(func):
def wrapper():
start_time = time.time()
res = func() # 执行被装饰方法
stop_time = time.time()
print("运行时间: %s" % (stop_time - start_time))
return res # 接受正在调用的方法的返回值,并返回
return wrapper
@timer
def test():
time.sleep(3)
print("test sleep 3s")
return "test return ok"
print(test()) # 执行的是 wrapper
# 结果:
# test sleep 3s
# 运行时间: 3.0002923011779785
# test return ok
4.2 被装饰方法带参数
import time
def timer(func):
"""
*args:将被修饰方法传入的非关键字参数打包为元组 args
**kwargs: 将被修饰方法传入的关键字参数打包为字典 kwargs
"""
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # *args 拆解元组,按顺序传给被修饰函数; **kwargs:拆解字典
stop_time = time.time()
print("运行时间: %s" % (stop_time - start_time))
return res
return wrapper
@timer # 给test 方法添加计算执行时间的装饰器
def test(name, age):
time.sleep(3)
print("name = {}, age = {}".format(name, age))
return "test return ok"
# 调用被装饰器装饰的方法
print(test("xu", 100)) # 执行的是 wrapper
# 结果:
# name = xu, age = 100
# 运行时间: 3.000420331954956
# test return ok
4.3 验证功能装饰器
假如 index() 、home()、shopping_car() 三个方法都需要登录后才能访问(无法访问时里面不输入对应内容),正常情况下只需登录一次,后面访问其他方法就无需再次登录。
可以通过@auth_fun装饰器进行验证用户是否登录,如果没有就让用户输入账号密码,用户账号密码正确的记录当前登录的用户,其他方法无需再次登录。
# 用户列表
user_list = [
{'name': 'xu1', 'passwd': '123'},
{'name': 'xu2', 'passwd': '123'},
{'name': 'xu3', 'passwd': '123'},
{'name': 'xu4', 'passwd': '123'},
]
# 当前登录的用户
current_dic = {"username": None, "login": False}
# 验证用户是否登录的装饰器
# 如果用户没有登录,让用户输入账号密码,校验通过记录用户状态
def auth_fun(func):
def wrapper(*args, **kwargs):
if current_dic["username"] and current_dic['login']:
res = func(*args, **kwargs)
return res
username = input("请输入用户名:")
pw = input("请输入密码:")
for u in user_list:
if u["name"] == username and u["passwd"] == pw:
current_dic["username"] = username
current_dic["login"] = True
res = func(*args, **kwargs)
return res
else:
print("用户没有注册!")
return wrapper
@auth_fun
def index():
print("this is index")
@auth_fun
def home():
print("this is home page")
@auth_fun
def shopping_car():
print("this is shopping car")
index() # 输入用户密码
home() # index 已经登录,无需在输入
shopping_car() # index 已经登录,无需在输入
# 结果:
# 请输入用户名:xu1
# 请输入密码:123
# this is index
# this is home page
# this is shopping car
4.4 验证功能装饰器——带参数
装饰器带参数,最简单的操作就是可以对被装饰的函数进行区别处理。
# 用户列表
user_list = [
{'name': 'xu1', 'passwd': '123'},
{'name': 'xu2', 'passwd': '123'},
{'name': 'xu3', 'passwd': '123'},
{'name': 'xu4', 'passwd': '123'},
]
# 当前登录的用户
current_dic = {"username": None, "login": False}
"""
注意:带参数的装饰器会比没有带参数的装饰器多嵌套一层函数(多了auth)
调用方式是 @auth(auth_type="type1"), 返回 auth_fun,
也就是说 @auth(auth_type="type1")相当于 @auth_fun
但是 auth_fun 函数所在的嵌套作用域多了一个 auth_type 的变量
"""
def auth(auth_type="type1"):
def auth_fun(func):
def wrapper(*args, **kwargs):
if auth_type == "type1":
if current_dic["username"] and current_dic['login']:
res = func(*args, **kwargs)
return res
username = input("请输入用户名:")
pw = input("请输入密码:")
for u in user_list:
if u["name"] == username and u["passwd"] == pw:
current_dic["username"] = username
current_dic["login"] = True
res = func(*args, **kwargs)
return res
else:
print("用户没有注册!")
elif auth_type == "type2":
print("不用授权直接登录: type = {}".format(auth_type))
res = func(*args, **kwargs)
return res
else:
print("其他type没有实现")
return wrapper
return auth_fun
"""
auth_fun = @auth(auth_type="type1")
auth_fun 所在的嵌套与将有一个 auth_type 变量
然后通过 @auth()方法返回的对象注解 index,相当于 @auth_fun 注解index 方法,最后得到 wrapper 对象
"""
@auth(auth_type="type1")
def index():
print("this is index")
@auth(auth_type="type2")
def home():
print("this is home page")
@auth(auth_type="type3")
def shopping_car():
print("this is shopping car")
home() # 注意:auth_type="type2",这个方法无需登录可以直接执行
index() # 注意:auth_type="type1",需要登录
shopping_car() # 注意:auth_type="type3",没有做处理
# 结果:
# 不用授权直接登录: type = type2
# this is home page
# 请输入用户名:xu1
# 请输入密码:123
# this is index
# 其他type没有实现
来源:https://blog.csdn.net/qq_30346413/article/details/115585209


猜你喜欢
- 本文实例讲述了Python计算回文数的方法。分享给大家供大家参考。具体如下:这里检查数字是不是回文数,用196算法生成一个数字的回文数num
- 关于Python的文件遍历,大概有两种方法,一种是较为便利的os.walk(),还有一种是利用os.listdir()递归遍历。方法一:利用
- 一、前言基于Mediapipe+Opencv实现手势检测,想实现一下姿态识别的时候,感觉手势识别也蛮重要的就过来顺便实现一下。下面是一些国内
- 枚举是常用的功能,看看Python的枚举.from enum import EnumMonth = Enum('Month'
- 今天研究了个开源项目,数据库是mysql的,其中的脚本数据需要备份,由于本人的机器时mac pro,而且mac下的数据库连接工具都不怎么好用
- 本文实例讲述了Go语言实现的树形结构数据比较算法。分享给大家供大家参考。具体实现方法如下:// Two binary trees may b
- 引言在使用SqlServer Express 版本的时候发现,这个版本不支持通过数据库的代理方式进行数据库的维护。解决方案使用SQL语句加w
- 1.order by rand()数据多了极慢,随机性非常好,适合非常小数据量的情况。SELECT * FROM table_name AS
- 暴力的重启服务方案一般服务器重启可以直接通过 kill 命令杀死进程,然后重新启动一个新的进程即可。但这种方法比较粗暴,有可能导致某些正在处
- Pillow图片格式转换Pillow 库支持多种图片格式,您可以直接使用 open() 方法来读取图片,并且无须考虑图片是何种类型。Pill
- 在vue的开发过程中,数据的绑定通常来说都不用我们操心,例如在data中有一个msg的变量,只要修改它,那么在页面上,msg的内容就会自动发
- 本文实例为大家分享了python画中国国旗的具体代码,供大家参考,具体内容如下# author : momoimport turtle#中国
- 引言如果熟悉使用JDBC来连接数据库的同学一定很清楚连接数据库的代码中一定会有依据Class.forName("com.mysql
- 如下所示,代码为:array也可直接使用上面代码。测试如下:来源:https://blog.csdn.net/u011624019/arti
- 本章节将为大家介绍Python循环语句的使用。Python中的循环语句有 for 和 while。Python循环语句的控制结构图如下所示:
- 前言本文主要介绍的是关于python中open函数用法的相关资料,用法如下:name = open('errname.txt'
- 内容简介展示如何给图像叠加不同等级的椒盐噪声和高斯噪声的代码,相应的叠加噪声的已编为对应的类,可实例化使用。以下主要展示自己编写的:加噪声的
- 项目中使用mp3格式进行音效播放,遇到一个mp3文件在程序中死活播不出声音,最后发现它是wav格式的文件,却以mp3结尾。要对资源进行mp3
- Python自带一个轻量级的关系型数据库SQLite。这一数据库使用SQL语言。SQLite作为后端数据库,可以搭配Python建网站,或者
- 本文实例为大家分享了python opencv实现图像配准与比较的具体代码,供大家参考,具体内容如下代码 from skimage