装饰器
闭包
闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包。
def decorator(par): #定义一个外部函数
def wrapper(kkk): #定义一个内部函数
test = par + kkk #内部函数使用了外部函数的参数
print(test)
return wrapper #返回了内部函数的引用
if __name__ == "__main__":
tt = decorator('mmm')
tt('nnn')
# 输出结果
# mmmnnn
装饰器
python 中的装饰器用@符号来表名,常见的代码是在函数名字上面@classmethod,@+函数名是python中的一种语法糖,因为解释器会对这种语法做特殊处理。
@decorator #等价于 func = decorator(func)
def func():
pass
下面通过代码简单说一下装饰器
def decorator(func):
def wrapper():
print("装饰前------decorator---")
func()
print("装饰后------decorator---")
return wrapper
def decorator1(func):
def wrapper1():
print("装饰前-----decorator1***********")
func()
print("装饰后-----decorator1*********")
return wrapper1
@decorator #等价于 test = decorator(test)
def test():
print('test-------')
def test1():
print('test1*******')
#等价于 test3 = decorator1(test3),括号里test3等于下面等号左边的test3
@decorator1
@decorator #等价于 test3 = decorator(test3)
def test3():
print('test3&&&&&&&')
if __name__ == "__main__":
test()
test1 = decorator(test1)
test1()
test3()
输出结果如下:
装饰前------decorator---
test-------
装饰后------decorator---
装饰前------decorator---
test1*******
装饰后------decorator---
装饰前-----decorator1***********
装饰前------decorator---
test3&&&&&&&
装饰后------decorator---
装饰后-----decorator1*********
上面代码简单说明了装饰器的作用和实现原理,当有多个装饰器同时对一个函数进行装饰时,先装饰内层然后装饰外层
函数实现装饰器
函数的装饰器分为两种情况:被装饰的函数带有参数和返回值,装饰器带有参数,下面通过代码对这两种情况进行说明:
被装饰函数带有参数和返回值
def pre_decorator(par='pre_dec')
def decorator(fun):
def dec_fun(*args, **kwargs): #可变参数
print("装饰器的参数---%s" % pre)
print("装饰前-----------")
ret = fun(*args, **kwargs) #函数执行的地方
print("装饰后-----------")
return ret #被装饰函数没有返回值的时候为None
return dec_fun
return decorator
@decorator
def sum(a,b,c):
print('执行函数')
return a+b+c
if __name__ == "__main__":
test = sum(2,3,6)
print(test)
输出结果:
装饰前-----------
执行函数
装饰后-----------
11
函数装饰器带有参数
在阅读一些开源框架的代码的时候,经常会遇到装饰器带有参数,带有参数的装饰器能够进一步丰富装饰器的功能,当装饰器含有参数时,我们要想获取并利用装饰器的参数,需要在原来装饰器基础上再封装一层闭包,请看下面代码
def pre_decorator(par='pre_dec'): # 装饰器添加一个默认字符串
def decorator(fun):
def dec_fun(*args, **kwargs): # 可变参数
print("装饰器的参数---%s" % par)
print("装饰前-----------")
ret = fun(*args, **kwargs) # 函数执行的地方
print("装饰后-----------")
return ret # 被装饰函数没有返回值的时候为None
return dec_fun
return decorator
@pre_decorator('haha')
def sum(a,b,c):
print('执行函数')
return a+b+c
if __name__ == "__main__":
test = sum(2,3,6)
输出结果:
装饰器的参数---haha
装饰前-----------
执行函数
装饰后-----------
类实现装饰器
类装饰器不带有参数 和 带有参数,其实现方式有点区别
当类装饰器不带有参数
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('装饰前----------')
ret = self.func(*args, **kwargs)
print('装饰后----------')
return ret
# 当装饰器没有参数时,其本质还是等价于 sum = Decorator(sum),被装饰函数sum引用传到__init__()中
# 相当于实例化一个对象,对象后面加括号比如sum(), 要调用类中的__call__()
@Decorator # 相当于sum = Decorator(sum)
def sum(a, b, c):
print('执行函数--------')
return a+b+c
if __name__ == "__main__":
print(sum(1,2,3))
运行结果:
装饰前----------
执行函数--------
装饰后----------
6
类装饰器含有参数时
class Decorator(object):
def __init__(self, par=''):
self.par = par
print('类装饰器的参数是 %s' % self.par)
# 被装饰函数的引用传到__call__中,需要通过闭包来装饰
def __call__(self, func):
def dec_fun(*args, **kwargs):
print('装饰前----------')
ret = func(*args, **kwargs)
print('装饰后----------')
return ret
return dec_fun
# 当类装饰器含有参数时,其本质等价于 sum = Decorator(par='parameter')(sum)
# 那么此时装饰器的参数par='parameter'传到了__init__()中,而被装饰函数sum的引
# 用传到了__call__()中了
@Decorator(par='parameter') # 相当于 sum = Decorator(par='parameter')(sum)
def sum(a, b, c):
print('执行函数--------')
return a+b+c
if __name__ == "__main__":
print(sum(1,2,3))
输出结果:
类装饰器的参数是 parameter
装饰前----------
执行函数--------
装饰后----------
6