欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python闭包与装饰器--下篇

程序员文章站 2022-07-12 10:01:14
...

前提:
装饰器函数从另一个角度去看其实是一个接口约束,它必须接受一个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!

python闭包与装饰器--下篇

普通的类装饰器和类装饰器带参数对比
被修饰函数传递位置改变,普通类装饰器是在__init__时传入即创建实例对象时;类装饰器带参数是在__call__时传入,即__init__创建实例传入的是装饰器参数,在实例()时调用__call__时传入真正的被修饰的函数。

本文为个人学习见解,请各路大牛多多指导!!!

相关标签: # python python