python装饰器可以极大地方便我们在对于重复执行的代码却又不确定有多少方法重复执行时,大大简化任务
可以用在方法执行的前置条件,判断方法是不是要执行,比如权限
# -*- coding: utf-8 -*-
def w1(func):
def inner():
print("---正在验证权限---")
if True:
print("--有权限--")
else:
print("--无权限--")
func()
return inner
# @w1 等价于 f1 = w1(f1)
@w1
def f1():
print("---f1---")
@w1
def f2():
print("---f2---")
f1()
f2()
打印结果如下:
---正在验证权限---
--有权限--
---f1---
---正在验证权限---
--有权限--
---f2---
若是有多个装饰器,那么从最上面的装饰器开始,把其下面的装饰器和方法都当做一个整体进行执行
# -*- coding: utf-8 -*-
def zhuangShi1(func):
def inner():
print("---1---")
return "第一次添加---" + func()
return inner
def zhuangShi2(func):
def inner():
print("---2---")
return "第二次添加---" + func()
return inner
@zhuangShi1
@zhuangShi2
def f1():
return "原始方法"
res = f1()
print(res)
打印结果如下:
---1---
---2---
第一次添加---第二次添加---原始方法
注意,如果有两层装饰器,并且在装饰器装饰时有执行代码,那么在装饰的时候,先走里面再走外面.在运行的时候,先运行外面载运行里面.
可以想象成身份证被包裹成邮件,包裹的时候,先看到身份证,最后再在外层包裹上写上地址信息.而拿到包裹时,先看到包裹上面的地址信息,拆开后才能看到身份信息
# -*- coding: utf-8 -*-
def zhuangShi1(func):
print("正在装饰1") # 这是在最外层包裹
def inner():
print("---1---") # 这是外层执行
return "第一次添加---" + func()
return inner
def zhuangShi2(func):
print("正在装饰2") # 这是里层包裹
def inner():
print("---2---") # 这是里层执行
return "第二次添加---" + func()
return inner
@zhuangShi1
@zhuangShi2
def f1():
return "原始方法"
res = f1()
print(res)
输出结果是:
正在装饰2
正在装饰1
---1---
---2---
第一次添加---第二次添加---原始方法
如果对于带有参数的装饰起来说,只需要在装饰器方法的闭包加参数,在闭包中调用方法时也加上参数即可
def zhuangShi(func):
print("---不定长参数的装饰器---")
def inner(*args, **kwargs): # 这里加上参数
print("---inner---")
func(*args, **kwargs) # 这里传入参数
return inner
@zhuangShi
def func1(a, b, c):
print("a = %d, b = %d, c = %d"%(a, b, c))
@zhuangShi
def func2(a, b, e):
print("a = %d, b = %d, e = %d"%(a, b, e))
func1(1,2,3)
func2(11,22,e=33)
输出结果是:
---不定长参数的装饰器---
---不定长参数的装饰器---
---inner---
a = 1, b = 2, c = 3
---inner---
a = 11, b = 22, e = 33
如果函数带有返回值,那么只需要在闭包中把返回值保存,然后再在最后把得到的返回值返回即可
def zhuangShi(func):
print("---不定长参数的装饰器---")
def inner(*args, **kwargs):
print("---inner---")
res = func(*args, **kwargs) # 这里将之前的函数返回值保存起来
return res # 把函数返回值返回
return inner
@zhuangShi
def func1(a, b, c):
print("a = %d, b = %d, c = %d"%(a, b, c))
return "hahaha"
res = func1(1,2,3)
print("res is %s"%res)
输出结果为:
---不定长参数的装饰器---
---inner---
a = 1, b = 2, c = 3
res is hahaha
通用装饰器,适合有无返回值,有无参数,都可以
# 通用装饰器
def zhuangShi(func):
def inner(*args, **kwargs):
print("通用装饰器---打印日志")
res = func(*args, **kwargs)
return res
return inner
@zhuangShi
def test1():
print("-----test1----- 带返回值")
return "test返回值"
@zhuangShi
def test2():
print("-----test2----- 不带返回值")
@zhuangShi
def test3(a):
print("-----test3----- 带参数,参数a = %d"%a)
res = test1()
print("test1 的返回值是: %s"%res)
test2()
test3(45)
输出结果:
通用装饰器---打印日志
-----test1----- 带返回值
test1 的返回值是: test返回值
通用装饰器---打印日志
-----test2----- 不带返回值
通用装饰器---打印日志
-----test3----- 带参数,参数a = 45
对于带参数的装饰器,则需要在寻常装饰其方法外再包一层函数
def zhuangShi(arg): # 常见装饰器方法外再包一层
def zhuangShi_in(func): # 装饰器方法
def inner():
print("--带有参数的装饰器--%s"%arg)
func()
return inner
return zhuangShi_in # 这里要返回装饰器方法
@zhuangShi("--哈哈哈哈哈--")
def test():
print("test")
test()
输出结果
--带有参数的装饰器----哈哈哈哈哈--
test
类装饰器, 使用一个类来当做函数的装饰器, 要用到类的call( ) 方法,此方法可以使类能够像函数那样通过类名直接调用call方法
class Test(object):
def __init__(self, func):
print("--类装饰器初始化--")
print("被装饰的方法名是: %s"%func.__name__)
self.__func = func
#__call__方法可以使类名能够像方法一样直接被调用
def __call__(self):
print("--装饰器中的功能--")
self.__func()
@Test #装饰器相当于 test = Test(test)
def test():
print("-------test方法---------")
test()
输出结果是:
--类装饰器初始化--
被装饰的方法名是: test
--装饰器中的功能--
-------test方法---------