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!

未完待续。。。

 
原文地址:https://www.cnblogs.com/ccorz/p/5550527.html