zoukankan      html  css  js  c++  java
  • python装饰器详解,多层装饰器,类装饰器,及带参数的装饰器。

    pyhon学习有一段时间了,今天又碰到了Django的中间件,其实Django里面的中间件,就是用了多层的装饰器,然后去了解了一下多层装饰器,感觉有写东西差不多快忘了,也可能前面没学好。

    现在重新记录,学习下。

    普通简单装饰器

    def warp(func):
        print('我是装饰器,碰到需要装饰的函数,一开始执行这里')
        def inner(*args, **kwargs):
            print('这里才是真正的装饰开始!')
            res = func(*args, **kwargs)
            print('装饰结束')
            return res
        print('我这里是外围,先出去了,里面的等需要的时候执行')
        return inner
    
    @warp   # 装饰器符号
    
    
    def demo(x, y):
        return x + y
    
    if __name__ == '__main__':
        demo(1, 2)
    
    运行结果:
    我是装饰器,碰到需要装饰的函数,一开始执行这里
    我这里是外围,先出去了,里面的等需要的时候执行
    这里才是真正的装饰开始!
    装饰结束
    

    装饰器的本质就是一个函数,当你写好装饰器的函数从上而下运行时,一旦遇到@的提醒,python应该就开始进入准备状态寻找需要装饰的函数,当遇到下面一个需要被装饰的函数demo时,

    整个过程我在debug过程中发现,其实python马上跳转到开始去执行了warp函数,这就是刚开始我们输出前面两句的原因,其实这个时候,程序根本没有执行到demo(1,2)的地方。

    在这个warp 程序的运行过程中,还发生一个命名转换的过程,就是demo=warp(demo),其实就是demo等于warp执行返回的函数inner,所以最后面执行demo(1,2)的时候,装饰器开始工作。

    理解了这个,后面多层的装饰器更加好理解了。

    简单来说,装饰器是一个可调用对象,但返回的还是一个可调用对象。

    下面上一个最简单的两层装饰器。

    def deco1(func):
        print('func 1 in')
        def wrapper1():
            print('wrap1 in')
            func()
            print('wrap1 out')
        print('func 1 out')
        return wrapper1
    
    def deco2(func):
        print('func 2 in')
        def wrapper2():
            print('wrap2 in')
            func()
            print('wrap2 out')
        print('func 2 out')
        return wrapper2
    
    @deco1
    @deco2
    def foo():
        print('foo')
    
    
    if __name__ == '__main__':
        foo()
    

     执行结果为:

    func 2 in
    func 2 out
    func 1 in
    func 1 out
    wrap1 in
    wrap2 in
    foo
    wrap2 out
    wrap1 out

    其实一开我因为没能理解装饰器的原理在两个地方卡住了,第一个就是为什么先出的是

    func 2 in
    func 2 out
    func 1 in
    func 1 out

    第二个问题就是为什么foo函数执行了一次,第二问题,网上查到了资料,第一个问题,通过对装饰的理解和debug的过程,也理解了。

    通过介绍,整个程序是至上而下运行的,在运行过程到

    @deco1

    @deco2

    def foo():

     一遇到需要装饰的函数def的时候,用要开始重新走装饰器,在走的过程中,先走跟函数近的装饰器deco2,所以输出了
    func 2 in
    func 2 out
    再走deco1,所以输出了
    func 1 in
    func 1 out

    回头来看就好理解多了,多层装饰,装饰器函数除了返回的内部函数不执行。函数体内会执行。就脚本执行的时候先执行foo=deco1(deco2(foo))

    所以先执行了装饰函数内的print输出,当执行foo()函数的时候,

    首先要执行deco1装饰器内的wrapper1()函数,当wrapper1()函数执行到func()的时候,会去执行deco2装饰器返回的wapper2函数,因为wrapper1内的func就是deco2装饰器中的wrapper2

    wrapper2中的func位被装饰的函数foo。好心累。

    最后一个带参数的装饰器。
    这个更加像一个内部返回来两次函数的定义函数,一共需要三个def来写这个函数。

    为什么需要三个def,很简单因为带参数的装饰器在@func()这样的时候,已经消耗了一个def。

    def deco(params):     # params 为需要传入的参数
        print('floor1')
        def inner(func):
            print('floor2')
            def warp(*args, **kwargs):
                print('floor3')
                print('装饰开始')
                for i in range(params):
                    func(*args, **kwargs)
                print('装饰结束')
                print('out3')
            print('out2')
            return warp
        print('out1')
        return inner
    
    
    @deco(5)        #这个就是生成一个函数warp指向demo
    
    def demo():
        print('ok')
    
    if __name__ == '__main__':
        demo()
    

     执行结果:

    /Users/shijianzhong/Desktop/swiper/.venv/bin/python /Users/shijianzhong/Desktop/swiper/paramsfunc.py

    floor1
    out1
    floor2
    out2
    floor3
    装饰开始
    ok
    ok
    ok
    ok
    ok
    装饰结束
    out3
    

    三层装饰器,简单的理解就是一个装饰器工厂,运行@func()的时候,func()将返回一个装饰器给需要装饰的对象用。

    带参数的装饰器,也可以用类写,参考链接:https://blog.csdn.net/weixin_43751803/article/details/86491529

    class Decorate(object):
    	"""将最终返回的函数名更新为func原始函数名"""
        def __init__(self, func):
            print('装饰器初始化',func.__name__)
            self.__func = func
            self.__name__ = Decorate.__name__
    
        @classmethod
        def set_name(cls,update_func):
            cls.__name__ = update_func.__name__
            print(cls.__name__)
            return cls
    
        def __call__(self, *args, **kwargs):
            print('装饰器功能')
            self.__func(*args, **kwargs)
    
    def decorater(func):
        @Decorate.set_name(func)
        def wrapping(*args,**kwargs):
            print('执行函数',func.__name__)
            return func(*args,**kwargs)
        return wrapping
    
    @decorater
    def test(a,b):
        print(a+b)
    
    test(2,3)
    print('返回的函数名',test.__name__)
    

    作者对装饰器的理解还是蛮厉害的,通过类方法,给类添加一些属性,然后然后自己。

    后期的返回的装饰器类,实例以后调用类属性,逻辑还是非常清晰可用的。

  • 相关阅读:
    人为什么会生气 --- 答案是什么?
    职场中我们常犯的8个错误
    职场上最常见的20条错误,犯三条就够致命啦
    C语言,基于单向链表实现,变长动态数据缓冲区(线程安全) ---- 类似java的StringBuffer --- 亲测OK
    门限签名
    基于RSA的实用门限签名算法
    图解密码技术(第3版)-第4章
    各种加密算法比较
    密码那点事儿
    数字签名,我有疑问。
  • 原文地址:https://www.cnblogs.com/sidianok/p/11564311.html
Copyright © 2011-2022 走看看