zoukankan      html  css  js  c++  java
  • python基础之:九步认识装饰器

    step1.

    先看个代码吧:

    def f():
        print('111111')
    
    f=lambda a:a +100  #覆盖上面的函数f
    
    print(f)  #函数名指函数所在内存中的位置,入带后面括号表示执行函数
    print(f(10))
    
    out:
    <function <lambda> at 0x101b7b6a8>
    110

    以上code说明:

    1.在def 函数时,以顺序执行,如果相同的函数名,会被最后函数覆盖以前的

    2.如果直接func名而没有后面的圆括号的话,只指向函数在内存中的位置

    3.lambda表达式会自动return结果,而def需要定义return值


    step2:

    python中可想函数传递参数,并将参数转变为本地变量存在于函数内部。

    def f(x):
        print(locals())
    
    f('a')
    
    out:
    
    {'x': 'a'}

    step3:

    python函数中可以嵌套函数,这就说明了我们可以在函数里定义函数,而且现有的作用域和函数的变量生存周期依旧适用。

    def outer():
        x='hello world'
        def inner():
            print(x)    #1
        inner()          #2
    
    outer()
    
    out:
    hello world

    #1 中发生了什么,函数inner需要一个x的变量,去查找x的变量,但本地变量中没有,查找失败后去上一层的作用域中去寻找,而x变量在上一层函数的作用域中。

    对outer来说,x是本地变量,但函数inner可以访问封闭的作用域

    #2 中,调用了inner函数,python解释器会优先查找本地的变量x


    step4:

    def outer():
        x='hello world'
        def inner():
            print(x)
        return inner  #1
    
    foo=outer()  #2
    print(foo)
    foo()
    
    out:
    <function outer.<locals>.inner at 0x10137b6a8>
    hello world

    #1与step3区别,我们将函数inner的内存地址给返回了

    #2,将函数outer的返回值赋值于变量foo,也就是说,foo() 执行时,实际上执行了inner()。

    但inner函数集成了outer函数中的本地变量,outer外面,没有x这个变量,为什么能执行呢??

    这是因为python中有一个叫”函数闭包”的特性,怎么理解呢?嵌套定义在非全局作用域中的函数,能够记住它在被定义时候它所处的封闭命名空间。

    函数outer每次在被调用的时候,函数inner都会被重新定义,现在变量x的值不会变化,所以每次执行的逻辑和结果都一样,那么如果x是变化的呢?


    step5:

    def outer(x):
        def inner():  
            print(x)  #1
        return inner
    
    print1=outer(1)
    print2=outer(2)
    
    print1()
    print2()
    
    out:
    1
    2

    从这个我们能够看到“闭包”:被函数记住的封闭作用域,能够被用来创建自定义的函数。

    事实上,我们并不是传递参数1或2给inner函数,我们实际上是定义了能够打印各种数字的自定义版本。


    step6:装饰器

    终于说到装饰器上了。。。。。

    装饰器其实就是一个闭包而已,把func作为参数,然后返回一个替代版的函数,其实真正执行的是inner内部的流程

    def outer(func):
        def inner():
            print('before some_func')
            res = func()
            print(res+1)
            print(('after some_func'))
            return res+1
        return inner
    def foo():
        return 1
    f1=outer(foo)   #1
    f1()
    
    out:
    before some_func
    2
    after some_func

    在这我们可以认为变量f1是函数foo的的装饰器。但这么写有点太low了是不是,所以python中有个优雅的@符号,太装逼了。。。可以这么写:

    def outer(func):
        def inner():
            print('before some_func')
            res = func()
            print(res+1)
            print(('after some_func'))
            return res+1
        return inner
    @outer
    def foo():
        return 1
    foo()
    
    out:
    
    before some_func
    2
    after some_func

    看到没,执行结果一毛一样有木有。


    step7:
    装饰器用法:
    @+函数名
    功能:1.自动执行函数(outer函数),并且将下面的函数名f1当做参数
              2.将outer函数的返回值,重新赋值给f1 
    需要注意的两点:
    1.有return值得才是完整的装饰器。
    2.闭包中返回的inner必须是函数的名称func,并非是func(),如果带了括号,那就是执行函数了, inner中返回为None,因为inner中没有return或者return值为其他了。

    step8:
    有同志就问了,这特么是一个没有参数的,那如果我自己定义的函数有一个参数咋弄。
    那我们就用函数中的万能参数*args **kwargs来造一个通用的装饰器吧:
    def outer(func):
        def inner(*args,**kwargs):
            print('before some_func')
            res = func(*args,**kwargs)
            print(('after some_func'))
            return res
        return inner
    @outer
    def foo():
        print(111)
    foo()
    
    
    @outer
    def foo1(li,d):
        print('args:%s'%li)
        print('kwargs:%s'%d)
    foo1('fuck','U')
    ===============
    out:
    before some_func
    111
    after some_func
    before some_func
    args:fuck
    kwargs:U
    after some_func

    step9:

    多层装饰器

    装饰器类似于俄罗斯套娃,可以一层套一层,譬如:

    def outer(func):
        def inner(*args,**kwargs):
            print('before some_func')
            res = func(*args,**kwargs)
            print(('after some_func'))
            return res
        return inner
    
    @outer1
    @outer
    def foo1(li,d):
        print('args:%s'%li)
        print('kwargs:%s'%d)
    foo1('fuck','U')
    
    ====================
    out:
    before:this is outer1
    before some_func
    args:fuck
    kwargs:U
    after some_func
    after:this is outer1 again!

    未完待续。。。

     
  • 相关阅读:
    LeetCode153.寻找旋转排序数组中的最小值
    LeetCode88.合并两个有序数组
    分析树
    LeetCode119.杨辉三角 II
    ssh传输文件
    ubuntu arm妙算加载cp210x驱动
    terminator终端工具
    ros使用rplidar hector_mapping建地图
    launch文件
    eclipse配置ros cakin编译环境
  • 原文地址:https://www.cnblogs.com/ccorz/p/5550527.html
Copyright © 2011-2022 走看看