基于Python闭包及其作用域详解


Posted in Python onAugust 28, 2017

关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记

如果在一个内部函数里,对一个外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被称为闭包(closure),而这个被内部函数引用的变量则被成为自由变量

闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量

命名空间和作用域

我们把命名空间看做一个大型的字典类型(Dict),里面包含了所有变量的名字和值的映射关系。在 Python 中,作用域实际上可以看做是“在当前上下文的位置,获取命名空间变量的规则”。在 Python 代码执行的任意位置,都至少存在三层嵌套的作用域:

最内层作用域,最先搜索,包含所有局部变量(Python 默认所有变量声明均为局部变量)

所有包含当前上下文的外层函数的作用域,由内而外依次搜索,这里包含的是非局部也非全局的变量

一直向上搜索,直到当前模块的全局变量

最外层,最后搜索的,内置(built-in)变量

scopes = {
 "local": {"locals": None,
    "non-local": {"locals": None,
       "global": {"locals": None,
         "built-in": ["built-ins"]}}},
}

除了默认的局部变量声明方式,Python还有global和nonlocal两种类型的声明(nonlocal是Python3.x之后才有的),其中nonlocal是指最内层之外,global以内的变量。必须强调的是,最内层局部作用域对外层作用域的变量只有只读(read-only)的访问权限。比如下列的例子

x = 100
def main():
 x += 1
 print (x)
main()
UnboundLocalError Traceback (most recent call last)
<ipython-input-2-9ed43e483a17> in <module>()
  3 x += 1
  4 print(x)
----> 5 main()
<ipython-input-2-9ed43e483a17> in main()
  1 x = 100
  2 def main():
----> 3 x += 1
  4 print(x)
  5 main()
UnboundLocalError: local variable 'x' referenced before assignment

这里抛出UnboundLocalError,是因为main()函数内部的作用域对于全局变量x仅有只读权限,想要在main()中对x进行改变,不会影响全局变量,而是会创建一个新的局部变量,显然无法对还未创建的局部变量直接使用x += 1, 因为x未绑定到任何对象上。如果想要获得全局变量的完全引用,则需要global声明:

x = 100
def main():
 global x
 x += 1
 print(x)
main()
print(x) # 全局变量已被改变

# result: 
# 101
# 101

闭包

闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量。

看了上面的Python作用域规则后,我们可以仿照JavaScript写一个计数器的闭包:

"""
/* JavaScript Closure example */
var inc = function(){ 
 var x = 0;
 return function(){
 console.log(x++);
 };
};
var inc1 = inc()
var inc2 = inc()
"""

# Python
def inc():
 x = 0
 def inner():
  nonlocal x
  x += 1
  print(x)
 return inner
inc1 = inc()
inc2 = inc()
inc1()
inc1()
inc1()
inc2()


# result:
# 1
# 2
# 3
# 1

在这里,全局环境下不能获取到inc()中的局部变量x的,但是我们返回了inc()内部函数inner(),而inner()对inc()中的局部变量是有访问权限的。也就是说inner()将inc()局部作用域打包发送给了inc1和 inc2,从而使他们各自独立拥有了一块封闭起来的作用域,不受其他运行环境和全局变量的影响,因此称之为闭包。

上述代码中inc1和inc2各自有一块封闭起来的作用域,可以通过Online Python Tutor 可视化运行工具看相应的运行结果

基于Python闭包及其作用域详解

这篇基于Python闭包及其作用域详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python多进程通信Queue、Pipe、Value、Array实例
Nov 21 Python
批处理与python代码混合编程的方法
May 19 Python
深入理解python try异常处理机制
Jun 01 Python
python3.4下django集成使用xadmin后台的方法
Aug 15 Python
浅谈Python黑帽子取代netcat
Feb 10 Python
对python多线程中互斥锁Threading.Lock的简单应用详解
Jan 11 Python
python字典改变value值方法总结
Jun 21 Python
python实现把二维列表变为一维列表的方法分析
Oct 08 Python
关于numpy中eye和identity的区别详解
Nov 29 Python
Python多进程编程multiprocessing代码实例
Mar 12 Python
基于python3.7利用Motor来异步读写Mongodb提高效率(推荐)
Apr 29 Python
python实现爱奇艺登陆密码RSA加密的方法示例详解
May 27 Python
利用Python查看目录中的文件示例详解
Aug 28 #Python
Python如何通过subprocess调用adb命令详解
Aug 27 #Python
Python中序列的修改、散列与切片详解
Aug 27 #Python
Python正确重载运算符的方法示例详解
Aug 27 #Python
深入学习Python中的上下文管理器与else块
Aug 27 #Python
python利用MethodType绑定方法到类示例代码
Aug 27 #Python
Python中使用haystack实现django全文检索搜索引擎功能
Aug 26 #Python
You might like
php面向对象全攻略 (十二) 抽象方法和抽象类
2009/09/30 PHP
PHP函数之日期时间函数date()使用详解
2013/09/09 PHP
PHP面向对象之后期静态绑定功能介绍
2015/05/18 PHP
关于PHP 如何用 curl 读取 HTTP chunked 数据
2016/02/26 PHP
php常用的工具开发整理
2019/09/26 PHP
PHP实现抽奖功能实例代码
2020/06/30 PHP
参考:关于Javascript中实现暂停的几篇文章
2007/03/04 Javascript
国外的为初学者写的JavaScript教程
2008/06/09 Javascript
判断控件是否已加载完成的代码
2010/02/24 Javascript
jquery中插件实现自动添加用户的具体代码
2013/11/15 Javascript
NodeJS Web应用监听sock文件实例
2015/02/18 NodeJs
JS动态修改iframe内嵌网页地址的方法
2015/04/01 Javascript
Javascript中的getUTCHours()方法使用详解
2015/06/10 Javascript
超实用的JavaScript表单代码段
2016/02/26 Javascript
教你一步步用jQyery实现轮播器
2016/12/18 Javascript
js封装tab标签页实例分享
2016/12/19 Javascript
浅谈Node Inspector 代理实现
2017/10/19 Javascript
layer.confirm取消按钮绑定事件的方法
2018/08/17 Javascript
webuploader分片上传的实现代码(前后端分离)
2018/09/10 Javascript
PM2自动部署代码步骤流程总结
2018/12/10 Javascript
详解nodejs 开发企业微信第三方应用入门教程
2019/03/12 NodeJs
24个解决实际问题的ES6代码片段(小结)
2020/02/02 Javascript
详解微信小程序动画Animation执行过程
2020/09/23 Javascript
在antd Table中插入可编辑的单元格实例
2020/10/28 Javascript
Vue使用Ref跨层级获取组件的步骤
2021/01/25 Vue.js
[02:42]DOTA2英雄基础教程 杰奇洛
2013/12/23 DOTA
[05:15]DOTA2英雄梦之声_第16期_灰烬之灵
2014/06/21 DOTA
[01:35]辉夜杯战队访谈宣传片—LGD
2015/12/25 DOTA
python使用Flask操作mysql实现登录功能
2018/05/14 Python
python调用matlab的m自定义函数方法
2019/02/18 Python
python模拟实现分发扑克牌
2020/04/22 Python
船餐厅和泰晤士河餐饮游轮:Bateaux London
2018/03/19 全球购物
西班牙鞋子和箱包在线销售网站:zapatos.es
2020/02/17 全球购物
大学生职业生涯规划书模板
2014/01/03 职场文书
2015高中教师个人工作总结
2015/07/21 职场文书
一文读懂navicat for mysql基础知识
2021/05/31 MySQL