python闭包与装饰器--下篇
前提:
装饰器函数从另一个角度去看其实是一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。
Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()方法,那么这个对象就是callable的
call
class Hello():
def __call__(self):
print("call me!")
if __name__ == '__main__':
Test = Hello() #此处Hello类创建了一个实例
Test()
# 结果:
# call me!
小结:因为Hello()重写了__call__方法,所以Hello()的实例均可以以"对象名()"形式执行,即是一个callable对象。
基于类实现的装饰器
思路:
1.闭包的思路是传入一个被修饰函数返回一个内部函数。
2.因此可以给实例传入一个被修饰函数,然后实例callable并返回一个函数
3.实现:让类的__init__()接受一个函数,并且类重载__call__()然后返回一个函数,从而达到装饰器函数的效果。
class Hello():
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter function {func}()".format(func=self.func.__name__))
return self.func(*args, **kwargs)
def saysomething(something):
print ("say hello {}!".format(something))
if __name__ == '__main__':
saysomething = Hello(saysomething)# 类似闭包的书写方式
saysomething('world')
# 结果:
# [DEBUG]: enter function saysomething()
# say hello world!
利用闭包的原理结合类的特殊方法可以实现闭包,但是调用和书写形式上并不方便因此产生了类装饰器
class Hello():
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter function {func}()".format(func=self.func.__name__))
return self.func(*args, **kwargs)
@Hello #say=Hello(say)
def saysomething(something):
print("say hello {}!".format(something))
if __name__ == '__main__':
saysomething('world')
# 结果:
# [DEBUG]: enter function saysomething()
# say hello world!
类装饰器带参数
1.普通的装饰器是通过装饰器嵌套实现,因此类装饰器带参数也必须通过类似的嵌套,因此在构造函数里接受的就不是一个函数,而是传入的参数。
2.通过类把这些参数保存起来。然后在重载__call__方法是就需要接受一个函数并返回一个函数以此来实现内部的装饰器函数。
3.因此就是类内部包含了一个闭包,而不是类本身实现了闭包。
class Hello():
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def inner(*args, **kwargs):
print ("[{level}]: enter function {func}()".format( level=self.level, func=func.__name__))
func(*args, **kwargs)
return inner # 返回函数
@Hello(level='INFO')#saysomething=Hello('lvl1')(say)
def saysomething(something):
print("say hello {}!".format(something))
if __name__ == '__main__':
saysomething('world')
# 结果:
# [INFO]: enter function saysomething()
# say hello world!
普通的类装饰器和类装饰器带参数对比
被修饰函数传递位置改变,普通类装饰器是在__init__时传入即创建实例对象时;类装饰器带参数是在__call__时传入,即__init__创建实例传入的是装饰器参数,在实例()时调用__call__时传入真正的被修饰的函数。
本文为个人学习见解,请各路大牛多多指导!!!
上一篇: Azure cli安装学习
下一篇: Python:闭包与装饰器