python tips:最内嵌套作用域规则,闭包与装饰器
在作用域与名字空间提到,python是静态作用域,变量定义的位置决定了变量作用的范围。变量沿着local,global,builtins的路径搜索,直觉上就是从里到外搜索变量,这称为最内嵌套作用域规则。
从里到外的搜索
a = 1 def f():
a = 2
def b():
print(a)
b() f()
输出结果
2
最内嵌套作用域规则有一个神奇的特性,它对local变量的搜索只依赖于静态代码的组成,而与代码如何调用没有关系。
闭包
a = 1 def f():
a = 2
def b():
print(a)
return b b = f()
b()
输出结果
2
函数f返回函数b,在第九行调用f得到函数b,此时函数f调用完成,应该被销毁,它包含的局部变量a也应该随之销毁。所以调用函数b时应该得不到函数f的变量a才对,事实却相反,函数b打印出了本应被销毁的a变量。
局部作用域是静态实现的,跟代码如何调用,何时调用没有关系。对于局部变量a来说,它的作用域是函数f内,当然包含了函数b。而且在函数b中确实引用了a,为了让b在任何时候都能够得到它,a会将自己绑定到函数b上。
这样b得到了一个额外的变量a,在函数f被销毁后,仍然能够使用变量a。这种变量与函数绑定的结果称为闭包(closure),这种绑定的变量是静态变量(类似于为函数添加了属性)。
直观上,闭包的作用就是为函数添加静态变量。
函数计数器
def fn():
print("call fn") def count(fn):
i = [0]
def s(*arg):
i[0] += 1
print(f"times: {i[0]}")
fn(*arg)
return s fn = count(fn)
for _ in range(5):
fn()
输出结果
times: 1
call fn
times: 2
call fn
times: 3
call fn
times: 4
call fn
times: 5
call fn
有了闭包,不用传入额外的参数,函数自身就能记住状态的变化(闭包提供静态变量)。
装饰器
def count(fn):
i = [0]
def s(*arg):
i[0] += 1
print(f"times: {i[0]}")
fn(*arg)
return s @count
def fn():
print("call fn") for _ in range(5):
fn()
装饰器其实就是一个语法糖,fn上方加@count,等价于fn = count(fn)。
计数功能仍靠闭包实现。
@count必须出现在count定义函数之后,否则无法识别。
总结:
1. 最内嵌套作用域对于local变量的搜索只与代码组成有关,与动态运行环境无关
2. 闭包是外层变量与内层函数的绑定结果,主要作用是位函数添加静态变量
3. 装饰器是语法糖,装饰函数一般都返回一个闭包。
python tips:最内嵌套作用域规则,闭包与装饰器的更多相关文章
- 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!
Python函数定义.匿名函数.嵌套函数.闭包.装饰器 目录 Python函数定义.匿名函数.嵌套函数.闭包.装饰器 函数核心理解 1. 函数定义 2. 嵌套函数 2.1 作用 2.2 函数变量作用域 ...
- python 基础之第十天(闭包,装饰器,生成器,tarfile与hashlib模块使用)
局部变量与全局变量 局部变量:在函数里面定义的,只有当函数活动时才生效 全局变量:不在函数里面的 In [1]: x=10 In [2]: def bar(): ...: x=20 ...: prin ...
- Python--高阶函数、函数嵌套、名称空间及变量作用域、闭包、装饰器
1.高阶函数(map/reduce/filter) 高阶函数是指函数的参数可以是函数 这篇总结几个常用的高阶函数:map/reduce/filter map函数.reduce函数.filter函数都是 ...
- Python 变量作用域,闭包和装饰器
from dis import dis b = 6 def f1(a): print(a)print(b) b = 9 f1(3) print(dis(f1)) # dis模块可以查看python函数 ...
- 周末学习笔记——day01(函数,函数对象,嵌套调用,名称空间,作用域,闭包,装饰器)
一,复习 字符编码 文件头:py2—ASCII,py3—UTF-8 三种字符串:u' ' b ' ' r ' ' u' ' .endcode(' utf-8 ') b' '.deconde(' utf ...
- Python 名称空间与作用域、闭包与装饰器
Python 的名称 Python 的名称(Name)是对象的一个标识(Identifier).我们知道,在 Python 里面一切皆对象,名称就是用来引用对象的.说得有点玄乎,我们以例子说明. 例如 ...
- python函数作用域,闭包,装饰器
第一:函数作用域: L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间(闭包) G:global 全局作用域 B:build_in ...
- python中的生成器、迭代器、闭包、装饰器
迭代器 迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 可迭代对象 以直接作用于 for ...
- Python进阶(五)----内置函数Ⅱ 和 闭包
Python进阶(五)----内置函数Ⅱ 和 闭包 一丶内置函数Ⅱ ####内置函数#### 特别重要,反复练习 ###print() 打印输入 #sep 设定分隔符 # end 默认是换行可以打印到 ...
随机推荐
- 用Grails写单元测试
新的领域,多练练,这样写出的程序,确实坚固些. 也要理解集成测试与数据库相关,单元测试与类方法有关. 如果测试文件没有建立,按如下操作: Unit tests are generated automa ...
- 洛谷—— P2424 约数和
https://www.luogu.org/problem/show?pid=2424 题目背景 Smart最近沉迷于对约数的研究中. 题目描述 对于一个数X,函数f(X)表示X所有约数的和.例如:f ...
- 在shell脚本中使用函数的返回值
#!/bin/bash - function mytest() { echo "arg1 = $1" if [ $1 = "1" ] ;then return ...
- UISearchBar作为inputAccessoryView时的响应链
UISearchBar对象做为一个普通的视图对象加入到视图控制器的self.view中,定义.初始化.设置delegate.然后becomeFirstResponder,最后resignFirstRe ...
- luogu2828 [HEOI2016/TJOI2016]排序
题目大意 给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:(0,l,r)表示将区间[l,r]的数字升序排序:(1,l,r)表示将区间[l,r]的数字降序排序.最后询问第q位 ...
- mysql中DATETIME类型与TIMESTAMP的区别
1.DATETIME的日期范围是1001--9999年,TIMESTAMP的时间范围是1970--2038年. 2.DATETIME存储时间与时区无关,TIMESTAMP存储时间与时区有关,显示的值也 ...
- C++<iomanip>控制符
C++<iomanip>控制符 c++ cout 输出格式 在c++程序里面经常见到下面的头文件 #include <iomanip> io代表输入输出,manip是manip ...
- Codeforces--630C--Lucky Numbers(快速幂)
C - Lucky Numbers Crawling in process... Crawling failed Time Limit:500MS Memory Limit:65536K ...
- 支撑百亿级应用的 NewSQL
支撑百亿级应用的 NewSQL https://zhuanlan.zhihu.com/newsql/ 项目背景 初次接触 TiDB,是通过同程网首席架构师王晓波先生的分享,当时同程网正在使开发和数据库 ...
- Python的学习(二十一)----Python的静态变量
前段时间在论坛里面有人提问说, class foo(): member1 member2 ... self.member1 foo.member2 其中的两个成员member1, member2有什么 ...