您的位置:首页 > 编程语言 > Python开发

python的闭包,装饰器,@

2017-11-05 22:47 260 查看
一、闭包

问题描述:

def outer()

x = 1

def inner()

print x

return inner


fun = outer()

fun()


1)在inner()函数中引用了x,该变量是outer()临时作用域的

2)fun变量是函数inner()的函数对象,在调用fun时,可能outer的内层作用域已经销毁

3)由以上分析这就导致了调用fun()时会出错

而在python中不会出现以上情况,这叫做闭包,也就是在

fun = outer()


返回的inner()函数对象不仅仅是一个函数实体,还包括了该函数调用时程序上下文,对于inner()中引用到外部变量,会被保存起来(其实就是函数的调用环境,调用栈别被存起来了),当下一次调用fun的时候,就会重入,恢复之前的环境。这个其实类似于C++中函数对象,lamda,用一个私有变量保存外部参数。

二、装饰器

问题描述:

之所以叫装饰器,肯定是对函数做了一些修饰

def outer(fun):

def inner()

print 'before fun()'

ret = fun()

print 'after fun'

ret ret + 1

return inner

def fun():
return 1
decorate = outer(fun)
>>>decorate()
输出:
before fun()
after fun
2

这里outer就是一个装饰器,具体的装饰过程由inner来完成,根据之前提到的闭包来理解,返回了inner()函数(装饰的具体实施者),然后并把它赋值给decorate,在调用decorate时,函数fun()已经被修饰过了的版本,另外要注意inner函数是要被闭包的,才是最后实际执行的函数,被修饰的函数的名其实最后已经是另外一个函数,所以最后调用的时候,被修饰函数的参数一定要复合inner()的参数规定。比如

def outer(func)

def inner(a,b,c)

ret = func(a,b)

return ret + 1

return inner


def func(a,b)

return a + b

func = outer(func)

func(1,2,3)


这里最后调用func()的时候,参数一定要和inner()一致。但是一般不会这么写,那会使得调用很麻烦,还得去了解inner的参数。一种更方便的方法是把inner定义成

def inner(*args,**kwargs):



这样就可以接受任何参数,那么被修饰的函数的调用也比较随意了。不用刻意和inner匹配

这里进一步

func=outer(func)


这样就是利用outer装饰了函数自身,用新版本代替旧版本,其实装饰器最主要的作用是把一些不变的东西抽象出去,把变动的部分放进去了,我们只需要关注变动的部分,不变的部分不用太在意,这样提高开发效率。

三、使用@标识符,可以应用装饰器到函数上。

fun = outer(fun)


@outer

def fun():

return 1


这里的@outer效果和第一行效果一样,都是利用outer来装饰了fun,后续调用fun实际是调用outer中的inner函数。

注意:利用@只不过是第一行的一种省略写法,实际上outer任然被调用了,并且自己执行了自己的逻辑(一般都是一些预热准备工作),如flask的路由@route其实执行了route函数,并且在该函数中添加了URL的路由。这种@的写法会导致python解释器自动的调用route()函数,自动调用装饰函数,有多少个@就会调用多少次。这样完成了一些看不到的繁琐工作(类似于C++编译器自己所做的背后工作)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: