• 装饰器的学习 高级版-- 语法糖参数


    python装饰器的参数传递

     

    被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行)(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,会调用到装饰器内部的那个函数()

    装饰器:在不修改函数源代码的基础上,添加函数功能

    def log_time(func):  # 此函数的作用时接受被修饰的函数的引用test,然后被内部函数使用
        def make_decorater():
            print('现在开始装饰')
            func()
            print('现在结束装饰')
        return make_decorater  # log_time()被调用后,运行此函数返回make_decorater()函数的引用make_decorater
     
    @log_time  # 此行代码等同于,test=log_time(test)=make_decorater
    def test():
        print('我是被装饰的函数')
    test()  # test()=make_decorater()
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    现在开始装饰
    我是被装饰的函数
    现在结束装饰
    View Code

    当被装饰的函数有形参时

    def log_time(func):
        def make_decorater(*args,**kwargs):  # 接受调用语句的实参,在下面传递给被装饰函数(原函数)
            print('现在开始装饰')
            test_func = func(*args,**kwargs)  # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回
            print('现在结束装饰')
            return test_func  # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。
        return make_decorater
     
     
    @log_time
    def test(num):
        print('我是被装饰的函数')
        return num+1
     
    a = test(2)  # test(2)=make_decorater(2)
    print(a)
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    现在开始装饰
    我是被装饰的函数
    现在结束装饰
    View Code

    两个装饰器同时修饰一个函数(重点看执行顺序)

    如何理解顺序

    @log_time1是修饰@log_time2和test两个函数
    @log_time2只是修饰test一个函数
    def log_time1(func):
        def make_decorater(*args,**kwargs): 
            print('1现在开始装饰')
            test_func = func(*args,**kwargs) 
            print('1现在结束装饰') 
            return test_func 
        return make_decorater
     
    def log_time2(func):
        def make_decorater(*args,**kwargs):  # 接受调用语句的实参,在下面传递给被装饰函数(原函数)
            print('2现在开始装饰')
            test_func = func(*args,**kwargs)  # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回
            print('2现在结束装饰')
            return test_func  # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。
        return make_decorater
     
    @log_time1
    @log_time2
    def test(num):
        print('我是被装饰的函数')
        return num+1
     
    a = test(2)  # test(2)=make_decorater(2)
    print(a)
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    1现在开始装饰
    2现在开始装饰
    我是被装饰的函数
    2现在结束装饰
    1现在结束装饰
    3
    View Code

    如果语法糖带有参数:

    import time
    
    
    def foo(*args, **kwargs):
        def loo(func):
            print('from the loo', *args, **kwargs)
    
            def xoo(*args, **kwargs):
                print('from the xoo', *args, **kwargs)
                start_time = time.time()
                func(*args, **kwargs)
                stop_time = time.time()
                print('test time=%s' % (stop_time - start_time))
                print(*args, **kwargs)
    
            return xoo
    
        return loo
    
    
    @foo('hello from decoration')
    def test(*args, **kwargs):
        time.sleep(1)
        print('test is over')
    
    
    test('nihao', 'from the test')
    from the loo hello from decoration
    from the xoo nihao from the test
    test is over
    test time=1.0000572204589844
    nihao from the test
    View Code

    语法糖带有参数的目的是在原有装饰器的基础上,再加上一个参数, 根据参数在对内部函数进行装饰处理,所以有人给出2个装饰器装饰一个函数,就没有太大的必要性了, 完全可以在语法糖的基础上给予一个参数 ---可以是函数进行装饰

    所以对于2个装饰器的例子,我们可以这样修改一下:

    def foo(*args,**kwargs):
        print(*args,**kwargs)
        def log_time1(func):
            def make_decorater(*args, **kwargs):
                print('1现在开始装饰')
                test_func = func(*args, **kwargs)
                print('1现在结束装饰')
                return test_func
    
            return make_decorater
    
        return log_time1
    
    @foo('1来自语法糖的参数')
    def test(num):
        print('我是被装饰的函数')
        return num + 1
    
    a = test(2)  # test(2)=make_decorater(2)
    print(a)
    1来自语法糖的参数
    1现在开始装饰
    我是被装饰的函数
    1现在结束装饰
    View Code

    如何语法糖传入的参数是函数呢?

    我把上面2个语法糖的例子做了修改,看结果

    def foo(x):
        def log_time1(func):
            def make_decorater(*args, **kwargs):
                x()
                print('1现在开始装饰')
                test_func = func(*args, **kwargs)
                print('1现在结束装饰')
                return test_func
    
            return make_decorater
    
        return log_time1
    
    
    def goo():
        print('from the goo' )
    
    
    # @log_time1
    # @log_time2
    @foo(goo)
    def test(num):
        print('我是被装饰的函数')
        return num + 1
    
    
    #
    #
    a = test(2)  # test(2)=make_decorater(2)
    # print(a)
    from the goo
    1现在开始装饰
    我是被装饰的函数
    1现在结束装饰
    View Code

    语法糖的参数传递功能扩展了装饰器的功能。 

     部分内容来自于https://www.cnblogs.com/serpent/p/9445592.html

  • 相关阅读:
    java web开发中会遇到的异步执行方案
    MySQL中进行树状所有子节点的查询
    node.js ----NPM使用介绍
    Node.js--学习笔记
    node.js介绍及Win7环境安装测试(转)
    Jmeter中Websocket协议支持包的使用(转)
    jmeter---将回应数据写入到文件
    JMeter 插件 Json Path 解析 HTTP 响应 JSON 数据(转)
    python + Pyglet ---播放视频
    转 RTSP客户端模拟器(TCP方式,Python实现)
  • 原文地址:https://www.cnblogs.com/vincent-sh/p/12937725.html
Copyright © 2020-2023  润新知