• python装饰器的又一特性


    在之前一篇关于装饰器的文章中,介绍了装饰器的基本用法。

     1 def deco(render=None):
     2     def wrap(func):
     3         def wrapper(*args,**kwargs):
     4             result = func(*args,**kwargs) ###
     5             return render(result)  ###
     6         return wrapper
     7     return wrap
     8 
     9 
    10 my_render = lambda x: str(x) + ' --my_render'
    11 
    12 @deco(render=my_render)
    13 def test():
    14     return "this is test!"

    其中的过程大概是这样,最外层的函数deco,如果加上参数,说明运行这个函数并返回。

    最终这个装饰器返回的是wrapper,而不是第二层的wrap。为什么呢?

    究其原因,还是因为其实装饰器是闭包的一种特殊形式,闭包只有两层。

    典型的装饰器也只有两层,但如果想给装饰器加参数,就把接受参数的函数放到最外层。

    最外层的参数执行deco后,返回的是里层的两个函数,wrap和wrapper。

    被装饰的函数test执行后,返回了有最内层函数wrapper装饰后的结果。

    有一个特殊需求,我们想在被装饰的函数test还没有运行的时候,就完全执行装饰器。就是将三层函数都运行。

    记住一点:闭包只有两层,最外层是接受被装饰的函数。内层函数是被装饰的函数执行时运行的,它接受被装饰函数的参数。

    下面看一个例子,这个例子中有嵌套了四层:

     1 def wrap(t=1):
     2     print "in wrap"
     3     
     4     def wrapper(m=2):
     5         print "in wrapper"
     6         print "m is ", m
     7         
     8         def wrapper_1(func):
     9             print "in wrappper_1"
    10             
    11             def last_one(*args, **kwargs):
    12                 print "in last_one"
    13                 return func(*args, **kwargs)
    14             return last_one
    15         
    16         return wrapper_1
    17     
    18     return wrapper(33)
    19 
    20 @wrap()
    21 def test():
    22     print "test"

     最外层的wrap函数接受装饰器的参数。

    比较特别的是return wrapper(33)这一句,它将wrapper_1和last_one函数作为一个装饰器返回。

    看看运行结果:

    >>> from test_decorator import test
    in wrap
    in wrapper
    m is  33
    in wrappper_1
    >>> 
    >>> test()
    in last_one
    test
    >>> 
    >>> test
    <function last_one at 0x7f196e0548c0>

    导入test函数后,最终装饰test函数的是last_one函数。

    但我们还没有达到刚才提到的需求,我们想让被装饰的函数运行前,装饰器全部执行完毕。

    其实很简单,只要将函数改为三层嵌套,在第一层函数结束时调用执行第二层函数。

    给出最后的代码:

    def wrap(t=1):
        print "in wrap"
        
        def wrapper(m=2):
            print "in wrapper"
            print "m is ", m
            
            def wrapper_1(func):
                print "in wrappper_1"
                return func
            return wrapper_1
        
        return wrapper(33)
    
    @wrap()
    def test():
        print "test"

    看看它的执行结果:

    In [1]: from test_decorator_1 import test
    in wrap
    in wrapper
    m is  33
    in wrappper_1
    
    In [2]: test()
    test

    看到了吧,我们的装饰器完全执行了。

    其实只是在last_one函数里将test函数原样返回而已, 而且因为少了一层函数,所以就不能接收被装饰函数的参数了。

    但是这样也有一个特殊的应用场景,例如在原样返回test函数前,将test函数用其他方式生成新的对象并返回。

    如此以来当import完毕的时候,test函数已经变成另外一个对象了。可以变成一个类,等等。。。

  • 相关阅读:
    usaco contest
    chapter 2.getting started
    几种常见排序
    [usaco]Programming Contest Problem Types
    回溯实现组合问题
    第二章:循环结构程序设计
    第一章:程序设计入门
    第三章:数组和字符串
    数据库设计(一对一、一对多、多对多)
    linux与windows回车换行符的区别
  • 原文地址:https://www.cnblogs.com/huazi/p/2842250.html
Copyright © 2020-2023  润新知