python装饰器
【一】装饰器是什么?
???????在 Python 中,装饰器是一种特殊的语法结构,用于修改或增强函数或类的功能。它们可以将一个函数或类作为参数传递给另一个函数,并返回一个新的函数或类,以修改原始函数或类的行为。
装饰器通常用于以下场景:
- 记录函数执行时间
- 检查用户权限
- 缓存函数结果
- 添加日志记录
- 增加函数重试机制
- 实现单例模式等
示例:? ? ? #就是代表的运行结果
def my_decorator(func):
def wrapper():
print("代码执行前的函数参数.")
func()
print("代码执行后的函数参数.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
#代码执行前的函数参数.
#Hello!
#代码执行后的函数参数.
?????????在这个例子中,我们定义了一个名为
my_decorator
的装饰器函数,它将一个函数作为参数。装饰器函数中定义了一个名为wrapper()
的嵌套函数,它在调用被装饰函数之前和之后打印一些信息。最后,装饰器函数返回这个嵌套函数。????????使用
@my_decorator
语法将say_hello()
函数传递给my_decorator
装饰器进行装饰。这意味着当我们调用say_hello()
函数时,实际上是调用了wrapper()
函数。
【二】 装饰器的分类
主要分为两种:有参装饰器和无参装饰器
二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。
【三】 什么时候需要装饰器
?
1. 什么时候需要用装饰器?
试想你有一系列函数,例如如下所示的两个函数(分别计算和与积):
def my_sum_function(*args):
print("The sum is", sum(args))
def my_product_function(*args):
res = 1
for x in args:
res *= x
print("The product is", res)
my_sum_function(1, 2, 3, 4)
my_product_function(1, 2, 3, 4, 5)
现在,你需要为这一系列函数添加一个一样的功能,就是统计输入参数的个数,同时检查里面是否有0,那么低阶的解决方法就是为每一个函数单独添加部分代码,即
def my_sum_function(*args):
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print(" 输入参数包含0:", contain_zero) # 重复部分
print("The sum is", sum(args))
def my_product_function(*args):
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print("输入参数包含 0:", contain_zero) # 重复部分
res = 1
for x in args:
res *= x
print("The product is", res)
my_sum_function(1, 2, 3, 4)
my_product_function(0, 1, 2, 3, 4, 5)
这样写的话,代码中存在大量重复的部分,有没有好一点的办法呢?也许你已经想到了,就是把添加的这部分功能封装成一个单独的函数,然后让每一个函数单独调用这个函数(嵌套调用),这样就能减少写代码过程中的“Ctrl+C和Ctrl+V”,即
def my_sum_function(*args):
additional_function(*args) # 嵌套调用
print("The sum is", sum(args))
def my_product_function(*args):
additional_function(*args) # 嵌套调用
res = 1
for x in args:
res *= x
print("The product is", res)
def additional_function(*args):
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print("输入参数包含 0:", contain_zero)
my_sum_function(1, 2, 3, 4)
my_product_function(0, 1, 2, 3, 4, 5)
那有没有更pythonic的写法呢?这里就可以用到装饰器了,实现方法如下
def a_decorator(f):
def additional_function(*args):
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print("输入参数包含 0:", contain_zero)
f(*args)
return additional_function
@a_decorator
def my_sum_function(*args):
print("The sum is", sum(args))
@a_decorator
def my_product_function(*args):
res = 1
for x in args:
res *= x
print("The product is", res)
my_sum_function(1, 2, 3, 4)
my_product_function(0, 1, 2, 3, 4, 5)
2. 装饰器的执行机制
现在我么已经知道了装饰器的使用场景:就是为函数定制化额外功能的时候,可是添加装饰器。使用装饰器可以使代码更加简洁。那么装饰器是如何工作的呢?我们以如下例子说明:
def a_decorator(f): # 函数作为参数被传入
print(f"Function {f.__name__} is passed as the augument!")
def additional_function(*args): # 函数嵌套
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print("输入参数包含 0:", contain_zero)
f(*args) # 最终执行目标函数my_sum_function的地方
return additional_function # 函数作为返回对象
@a_decorator
def my_sum_function(*args):
print("The sum is", sum(args))
my_sum_function(1, 2, 3, 4)
# Function my_sum_function is passed as the augument!
# No.args is 4
# 输入参数包含 0: False
# The sum is 10
在进一步解释运行机制之前,我们需要明确几个问题:
- 一、在Python中,一切皆对象,包括函数。一个函数可以作为另一个函数的参数,一个函数也可以作为另一个函数的返回对象;
- 二、如果在一个函数体中定义了另一个函数,称为函数嵌套,前者称为enclosing function,后者称为enclosed function或者nested function
根据运行结果,我们可以反推出装饰器的工作机制:
- my_sum_function作为参数传入a_decorator函数,并开始执行,因此首先打印出“Function my_sum_function is passed as the augument!”
- 随后a_decorator函数执行过程中返回了additional_function函数对象,然后开始执行additional_function(1, 2, 3, 4),于是打印出“No. of input args is 4”和“Input arguments contain 0: False”
- 在additional_function函数嵌套调用了my_sum_function函数,因此最后打印“The sum is 10”
也就是说,上述例子如果不用@符号,和下面是完全等价的
def a_decorator(f):
print(f"Function {f.__name__} is passed as the augument!")
def additional_function(*args):
print("No.args is", len(args)) # 重复部分
contain_zero = any([x == 0 for x in args]) # 重复部分
print("输入参数包含 0:", contain_zero)
f(*args) # 最终执行目标函数my_sum_function的地方
return additional_function
def my_sum_function(*args):
print("The sum is", sum(args))
a_decorator(my_sum_function)(1, 2, 3, 4) # 注意理解这一行
【四】无参装饰器
无参装饰器模板
def outter(func):
def wrapper(*args,**kwargs):
#1 调用原函数
#2 为其增加新功能
res=func(*args,**kwargs)
return res
return wrapper
?示例:
import time
# 装饰器
def timmer(func):
def wrapper(*args,**kwargs):
start=time.time()
res=func(*args,**kwargs)
stop=time.time()
print(stop-start)
return res
return wrapper
这就不能在提python自带的一种机制了语法糖?:
在被装饰对象正上方的单独一行写@装饰器名称
@timmer ##index=timmer(index)
def index(x,y,z):
time.sleep(2)
print('index %s %s %s ' %(x,y,z))
@timmer ##home=timmer(123)
def home(name):
time.sleep(2)
print('welcome %s to home page' %name)
index(x=1,y=2,z=3)
home('jobin')
?
输出结果:?
index 1 2 3
2.0001492500305176
welcome jobin to home page
2.0004379749298096
其中
????????????????????????@timme ==? home = timmer(home)
我们还可以按照位置传值
def outer(func):
def inner(*args):
print(f"装饰器的args内容>>>{args}")
name = "tom"
age = "12"
res = func(name, age)
# res = func(*args)
# res = func(name, age, *args)
return res
return inner
@outer
def func(*args):
print(f"func中args中的内容>>>{args}")
func("lucy", "15")
#装饰器的args内容>>>('lucy', '15')
#func中args中的内容>>>('tom', '12')
【五】有参装饰器?
def 有参装饰器(x,y,z):
def outter(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
return res
return inner
return outter
@有参装饰器(1,y=2,x=3)
def 被装饰对象():
pass
被装饰对象()
?上点难度:
def login(func):
def inner(*args, **kwargs):
# 输入用户名和密码
username = input('请输入用户名:')
password = input('请输入密码:')
# 如果是管理员账户,则直接登录成功
if username == 'admin' and password == '12186':
print('欢迎尊敬的管理员')
else:
# 否则尝试从文件中读取用户记录
with open('01.txt', 'r', encoding='utf-8') as f:
for line in f:
values = line.strip().split(":")
if len(values) < 3:
print(f'记录格式不正确:{line}')
continue
# 匹配用户名和密码
new_username, new_password, age, gender, bankcard, withdraw_password, balance = values
if username == new_username and password == new_password:
print('用户登录成功')
return func( *args, **kwargs)
print('用户名或密码错误')
return False
return inner
@login
def test(admin = False):
if admin:
print('欢迎尊贵的管理员')
else:
print('欢迎平民')
# 调用 test 函数
test()
总体来说,这段代码的执行流程如下:
- 定义装饰器?
login
,该装饰器接收一个函数作为参数,并返回一个新的内部函数?inner
。 - 在?
inner
?函数中,首先要求用户输入用户名和密码。 - 如果用户名和密码与管理员账户相同,则直接登录成功。
- 否则,尝试从文件中读取用户记录,并匹配用户名和密码。
- 如果用户名和密码匹配成功,则调用原始的?
test
?函数并返回其结果。 - 如果用户名和密码不正确,则打印错误信息并返回 False。
- 定义被装饰的函数?
test
,该函数默认不是管理员账户,并根据不同情况输出欢迎信息。 - 调用?
test
?函数时,会被装饰器?login
?拦截并执行相关逻辑。
?
代码多敲,薪资低不了
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!