前言
很多小伙伴可能对python里面的装饰器似懂非懂,不了解其中的运行原理,希望这篇文章可以对你们有帮助哦。
装饰器原则:1.不能改变原函数的调用方式和结果;2.加上装饰器后扩展原函数的功能。
一、装饰器实例展示和运行原理
# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : deacorater.py
# Time :2023/3/9 8:32
# Author :han qibao
# version :python 3.9
# Description:
"""
def lulu_gei_w(func): # func是一个函数,就是我们要装饰的函数对象
def wrapper(*args, **kwargs): # 可变参数
print("璐璐给adc释放了w技能")
func(*args, **kwargs)
return wrapper
@lulu_gei_w
def han_bing(num):
print(f"寒冰射手打出了{num}下普攻击")
定义了一个函数han_bing,和一个装饰器lulu_gei_w
下面采用pycharm的debug功能看下至此,程序运行了什么:
此时我们没做什么操作,python帮我做了一些事,han_bing函数作为参数,就传入了名叫lulu_gei_w的装饰器中,下面我们调用han_bing函数:
注意,这个时候,发现此时的han_bing函数已经不是原来的那个han_bing函数了,观察可以发现,python是把wrapper的地址给复制给了一个叫han_bing的变量,实际上执行的就是wrapper。
(使用pycharm的debug功能可以很好的展示装饰器是怎么运行的)
二、带返回值的装饰器
看一段代码:
# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : deacorater.py
# Time :2023/3/9 8:32
# Author :han qibao
# version :python 3.9
# Description:
"""
def lulu_gei_w(func): # func是一个函数,就是我们要装饰的函数对象
def wrapper(*args, **kwargs): # 可变参数
print("璐璐给adc释放了w技能")
func(*args, **kwargs)
return wrapper
@lulu_gei_w
def han_bing(num, total):
print(f"寒冰射手打出了{num}下普攻击")
return f"造成了{total}点伤害"
if __name__ == '__main__':
res = han_bing(3, 60)
print(res)
运行后如图:
明显,返回值没有了,这是因为在装饰器中没有返回的操作,修改如下:
def lulu_gei_w(func): # func是一个函数,就是我们要装饰的函数对象
def wrapper(*args, **kwargs): # 可变参数
print("璐璐给adc释放了w技能")
return func(*args, **kwargs)
return wrapper
再次执行:
这样就完成了带有返回值的装饰器了
三、带有参数的装饰器
这就是终极版本了,我们的装饰器也时候也需要传参,有人会说,那我直接在lulu_gei_w装饰器的那个func后面加形参不就好了,这是不对的,那个地方是python自己处理的,会把你后面装饰的函数名当做实参穿进去,你自己往里面塞算啥子。这个时候可以用到前面所学的知识闭包,闭包就给内部函数传递参数,如下:
# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : deacorater.py
# Time :2023/3/9 8:32
# Author :han qibao
# version :python 3.9
# Description:
"""
def outer_args(experi_total): # 这个是期望的总伤害,装饰器的参数
def lulu_gei_w(func): # func是一个函数,就是我们要装饰的函数对象
def wrapper(*args, **kwargs): # 可变参数
print("璐璐给adc释放了w技能")
res_inner = func(*args, **kwargs)
if res_inner >= experi_total:
print("伤害爆表")
else:
print("adc拉胯")
return res_inner
return wrapper
return lulu_gei_w
@outer_args(80)
def han_bing(num, total):
print(f"寒冰射手打出了{num}下普攻击")
return total # 这里为了做比较,把之前的输出字符串改成了返回一个int
if __name__ == '__main__':
res = han_bing(3, 60)
print(res)
运行结果:
总结
我们han_bing函数该怎么用还是怎么用,加上装饰器后,就可以实现更多的逻辑判断,细细评味哦!