Python中的作用域规则详解


Posted in Python onJanuary 30, 2015

Python是静态作用域语言,尽管它自身是一个动态语言。也就是说,在Python中变量的作用域是由它在源代码中的位置决定的,这与C有些相似,但是Python与C在作用域方面的差异还是非常明显的。

接下来会谈论Python的作用域规则,在这中间也会说明一下Python与C在作用域方面的不同。

在Python 2.0及之前的版本中,Python只支持3种作用域,即局部作用域,全局作用域,内置作用域;在Python 2.2中,Python正式引入了一种新的作用域 --- 嵌套作用域;在Python 2.1中,嵌套作用域可以作为一个选项被开启;嵌套作用域的引入,本质上为Python实现了对闭包的支持,关于闭包的知识,网上有很多解释,这里就不详细展开了。相应地,变量查找顺序由之前的LGB变成LEGB(L:Local,E:Enclosing,G:Global,B:Built-in)。

在Python中,并不是任何代码块都能引入新的作用域,这与C有很大的不同:

#include<stdio.h>

int main() {

    if(2 > 0) {

        int i = 0;

    }

    printf("i = %d", i);

    return 0;

}

在这段代码中,if子句引入了一个局部作用域,变量i就存在于这个局部作用域中,但对外不可见,因此,接下来在printf函数中对变量i的引用会引发编译错误。

但是,在Python中却并非如此:

if True:

    i = 0

print i

 在这段代码中,if子句并没有引入一个局部作用域,变量i仍然处在全局作用域中,因此,变量i对于接下来的print语句是可见的。

实际上,在Python中,只有模块,类以及函数才会引入新的作用域,其它的代码块是不会引入新的作用域的。

在Python中,使用一个变量之前不必预先声明它,但是在真正使用它之前,它必须已经绑定到某个对象;而名字绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量,不论这个名字绑定发生在当前作用域中的哪个位置。

def f():

    print i

f()

运行结果将显示:NameError: global name 'i' is not defined。Python首先在函数f的本地作用域中查找变量i,查找失败,接着在全局作用域和内置作用域中查找变量i,仍然失败,最终抛出NameError异常。

i = 0

def f():

    i = 8

    print i

f()

print i

运行结果显示:8和0。i = 8是一个名字绑定操作,它在函数f的局部作用域中引入了新的变量i,屏蔽了全局变量i,因此f内部的print语句看到的是局部变量i,f外部的print语句看到的是全局变量i。

i = 0

def f():

    print i

    i = 0

f()

运行结果显示:UnboundLocalError: local variable 'i' referenced before assignment。在这个例子当中,函数f中的变量i是局部变量,但是在print语句使用它的时候,它还未被绑定到任何对象之上,所以抛出异常。

print i

i = 0

不论是以交互的方式运行,还是以脚本文件的方式运行,结果都显示:NameError: name 'i' is not defined。这里的输出结果又与上一个例子不同,这是因为它在顶级作用域(模块作用域)的缘故。对于模块代码而言,代码在执行之前,没有经过什么预处理,但是对于函数体而言,代码在运行之前已经经过了一个预处理,因此不论名字绑定发生在作用域的那个位置,它都能感知出来。Python虽然是一个静态作用域语言,但是名字查找确实动态发生的,因此直到运行的时候,才会发现名字方面的问题。

在Python中,名字绑定在所属作用域中引入新的变量,同时绑定到一个对象。名字绑定发生在以下几种情况之下:

1.参数声明:参数声明在函数的局部作用域中引入新的变量;
2.赋值操作:对一个变量进行初次赋值会在当前作用域中引入新的变量,后续赋值操作则会重新绑定该变量;
3.类和函数定义:类和函数定义将类名和函数名作为变量引入当前作用域,类体和函数体将形成另外一个作用域;
4.import语句:import语句在当前作用域中引入新的变量,一般是在全局作用域;
5.for语句:for语句在当前作用域中引入新的变量(循环变量);
6.except语句:except语句在当前作用域中引入新的变量(异常对象)。

在Python中,类定义所引入的作用域对于成员函数是不可见的,这与C++或者Java是很不同的,因此在Python中,成员函数想要引用类体定义的变量,必须通过self或者类名来引用它。

嵌套作用域的加入,会导致一些代码编译不过或者得到不同的运行结果,在这里Python解释器会帮助你识别这些可能引起问题的地方,给出警告。

locals函数返回所有的局部变量,但是不会返回嵌套作用域中的变量,实际上没有函数会返回嵌套作用域中的变量。

Python 相关文章推荐
Python实现的HMacMD5加密算法示例
Apr 03 Python
python Web开发你要理解的WSGI &amp; uwsgi详解
Aug 01 Python
使用python批量读取word文档并整理关键信息到excel表格的实例
Nov 07 Python
由Python编写的MySQL管理工具代码实例
Apr 09 Python
基于django传递数据到后端的例子
Aug 16 Python
Python3 合并二叉树的实现
Sep 30 Python
python manage.py runserver流程解析
Nov 08 Python
Python调用Windows命令打印文件
Feb 07 Python
浅谈pytorch中的BN层的注意事项
Jun 23 Python
python如何变换环境
Jul 21 Python
python实现xml转json文件的示例代码
Dec 30 Python
Python函数式编程中itertools模块详解
Sep 15 Python
Python中使用Boolean操作符做真值测试实例
Jan 30 #Python
Python中的zip函数使用示例
Jan 29 #Python
Python的另外几种语言实现
Jan 29 #Python
python中使用xlrd、xlwt操作excel表格详解
Jan 29 #Python
Python中实现常量(Const)功能
Jan 28 #Python
Python使用random和tertools模块解一些经典概率问题
Jan 28 #Python
Python中的异常处理学习笔记
Jan 28 #Python
You might like
PHP使用者状态管理功能的应用
2006/10/09 PHP
用PHP4访问Oracle815
2006/10/09 PHP
在PHP中读取和写入WORD文档的代码
2008/04/09 PHP
php启用sphinx全文搜索的实现方法
2014/12/24 PHP
WordPress开发中用于标题显示的相关函数使用解析
2016/01/07 PHP
Yii数据模型中rules类验证器用法分析
2016/07/15 PHP
php使用正则表达式获取字符串中的URL
2016/12/29 PHP
php使用mysqli和pdo扩展,测试对比mysql数据库的执行效率完整示例
2019/05/09 PHP
web的各种前端打印方法之jquery打印插件PrintArea实现网页打印
2013/01/09 Javascript
js动态添加删除,后台取数据(示例代码)
2013/11/25 Javascript
使用js检测浏览器是否支持html5中的video标签的方法
2014/03/12 Javascript
js表头排序实现方法
2015/01/16 Javascript
使用mouse事件实现简单的鼠标经过特效
2015/01/30 Javascript
jQuery插件Validate实现自定义校验结果样式
2016/01/18 Javascript
需要牢记的JavaScript基础知识
2016/09/25 Javascript
如何清除IE10+ input X 文本框的叉叉和密码输入框的眼睛图标
2016/12/21 Javascript
详解webpack异步加载业务模块
2017/06/23 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
利用pm2部署多个node.js项目的配置教程
2017/10/22 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
详解vue引入子组件方法
2019/02/12 Javascript
js最实用string(字符串)类型的使用及截取与拼接详解
2019/04/26 Javascript
vue3.0自定义指令(drectives)知识点总结
2020/12/27 Vue.js
Python sqlite3事务处理方法实例分析
2017/06/19 Python
python 3.5实现检测路由器流量并写入txt的方法实例
2017/12/17 Python
python解决js文件utf-8编码乱码问题(推荐)
2018/05/02 Python
pandas中read_csv的缺失值处理方式
2019/12/19 Python
python ffmpeg任意提取视频帧的方法
2020/02/21 Python
Python GUI编程学习笔记之tkinter事件绑定操作详解
2020/03/30 Python
Bibloo荷兰:女士、男士和儿童的服装、鞋子和配饰
2019/02/25 全球购物
通信工程毕业生自荐信
2013/11/01 职场文书
数控专业大学生的自我鉴定
2013/11/13 职场文书
民事诉讼代理授权委托书范本
2014/10/08 职场文书
普通党员整改措施
2014/10/24 职场文书
单方投资意向书
2015/05/11 职场文书
python入门学习关于for else的特殊特性讲解
2021/11/20 Python