设为首页 加入收藏

TOP

Python装饰器与闭包
2019-08-04 00:10:54 】 浏览:43
Tags:Python 装饰

首先,在函数中是能访问全局变量的:


然后,在一个嵌套函数中,内层函数能够访问在外层函数中定义的局部变量:


上面的嵌套函数就是闭包。闭包是指延伸了作用域的函数,在其中能够访问未在函数定义体中定义的非全局变量。未在函数定义体中定义的非全局变量一般都是在嵌套函数中出现的。


上述示例中的变量a就是一个并未在函数bar中定义的非全局变量。对于bar来说,它有个专业名字,叫做自由变量


自由变量的名称可以在字节码对象中查看:


自由变量的值绑定在函数的__closure__属性中:


其中保存了对应自由变量的cell对象的序列,cell对象的cell_contents属性保存了变量的值:


两种情况下,都会报错。这并不是缺陷,而是Python的设计选择。Python不要求声明变量,但是会假定在函数定义体中赋值的变量是局部变量,以避免在不知情的情况下修改全局变量。


a += 1a = a + 1相同,编译函数的定义体时,会将a当做局部变量,不会当做自由变量保存。然后尝试获取a的值时,发现a并没有绑定值,于是报错。


解决这个问题的办法,一是将变量置于一些可变对象,如列表、字典中:


另外的方法就是使用global或者nonlocal将变量声明为全局变量或者自由变量:


当自由变量本身是可变对象时,是可以直接进行操作的:


装饰器是可调用对象,参数一般是另一个函数。装饰器可以以某种方式增强被装饰函数的行为,然后返回被装饰的函数或者将其替换成一个新的函数。


一个最简单的不做任何额外行为的装饰器:


decorate函数就是一个最简单的装饰器,使用方法:


Python为装饰器的使用提供了语法糖,可以简便的写为:


装饰器一个很重要的特性是它是导入时(加载模块时)运行的:


结果:


可以看到,装饰器是导入时运行的,而被装饰的函数是明确调用时运行的。


装饰器可以返回被装饰的函数本身,和运行时导入的特性结合起来,可以实现简单的注册器功能:


上述装饰器的例子都返回了被装饰的原函数,但装饰器的典型行为还是返回一个新函数:把被装饰的函数替换成新函数,新函数接受与原函数相同的参数,并且返回原函数本该返回的值。写法类似于:


这种情况下装饰器就使用到了闭包。java script中的防抖与节流函数就是这种典型的装饰器行为。新函数一般会使用外部装饰器函数中的变量当做自由变量,对函数作出某种增强行为。


举个例子,我们知道,当Python函数的参数是个可变对象时,会产生意料之外的行为:


输出:


这是因为,函数的参数默认值保存在__defaults__属性中,指向了同一个列表:


我们就可以用一个装饰器在函数执行前取出默认值做深复制,然后覆盖函数原先的参数默认值:


输出:


装饰器除了可以接受函数作为参数外,还可以接受其他参数。使用方法是:创建一个装饰器工厂,接受参数,返回一个装饰器,再把它应用到被装饰的函数上,语法如下:


在Web框架中,通常要将URL模式映射到生成响应的view函数,并将view函数注册到某些中央注册处。之前我们曾经实现过一个简单的注册装饰器,只是注册了view函数,却没有URL映射,是远远不够的。


在Flask中,注册view函数需要一个装饰器:


原理就是使用了装饰器工厂,可以简单的模拟一下实现:


输出:


还可以使用装饰器工厂来确定view函数可以允许哪些HTTP请求方法:


装饰器也是可以重叠使用的:


等同于:


装饰器的参数也可以是一个类,也就是说,装饰器可以装饰类:


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python Web开发中的WSGI协议简介 下一篇Python使用LDAP做用户认证

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目