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 默认是换行可以打印到 ...
随机推荐
- PatentTips - Power management implementation in an optical link
BACKGROUND INFORMATION Embodiments of the present invention are directed to optical links and, more ...
- [bzoj2086][Poi2010]Blocks_单调栈_双指针
Blocks bzoj-2086 Poi-2010 题目大意:题目链接. 注释:略. 想法:首先,不难发现,如果连续的一段数的平均值不小于输入的k的话,这段数是满足题意的. 所以,我们再次简化一下:将 ...
- Linux终止进程的工具kill/killall/pkill/xkill/skill用法区别(转)
一. 终止进程的工具kill .killall.pkill.xkill 终止一个进程或终止一个正在运行的程序,一般是通过kill .killall.pkill.xkill等进行.比如一个程序已经死掉, ...
- MySQL:解决MySQL无法启动的问题
MySQL无法启动的原因有多种,这里是我遇到的一种情况和解决方法. 起因: 最近项目需要使用MySQL,于是想在MAC上安装一个本地的数据库,但是其实忘了已经安装过一个版本了,结果发现新的服务器怎么也 ...
- ACdream 1112 Alice and Bob (博弈&&素数筛选优化)
题目链接:传送门 游戏规则: 没次能够将一堆分成两堆 x = a*b (a!=1&&b!=1)x为原来堆的个数,a,b为新堆的个数. 也能够将原来的堆的个数变成原来堆的约数y.y!=x ...
- SQL LEN() 函数 ,case when,聚合函数的使用方法
SELECT aa.[User_Id],cc.[User_Name],dd.Name AS DepName,aa.Module_Id,aa.Module_Name, SUM(CASE aa.Opera ...
- hdu 4850 字符串构造---欧拉回路构造序列 递归+非递归实现
http://acm.hdu.edu.cn/showproblem.php? pid=4850 题意:构造长度为n的字符序列.使得>=4的子串仅仅出现一次 事实上最长仅仅能构造出来26^4+4- ...
- iOS 推送证书的制作
关于iOS推送证书的P12文件,并非直接从KeyChain导出来的证书文件.而是须要经过openSSL工具制作的.(好在Mac OS 默认就有openSSL命令) 针对不同的Server平台,须要的证 ...
- 试试pypy
pypy是一个python的解释器和JIT编译器.能够在不改动不论什么代码的情况下大幅提升python代码的性能. 使用超级简单,在官网下载编译好的二进制包进行安装,然后然后执行代码的时候指定这个解释 ...
- bzoj 3029 守卫者的挑战 —— 概率DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3029 设 f[i][j][k] 表示第 i 次挑战,已经成功 j 次,剩余容量为 k 的概率 ...