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中操作文件之seek()方法的使用教程
May 24 Python
Python错误: SyntaxError: Non-ASCII character解决办法
Jun 08 Python
python基础_文件操作实现全文或单行替换的方法
Sep 04 Python
Python用于学习重要算法的模块pygorithm实例浅析
Aug 16 Python
Python命名空间的本质和加载顺序
Dec 17 Python
python实现的MySQL增删改查操作实例小结
Dec 19 Python
Python实现的爬取豆瓣电影信息功能案例
Sep 15 Python
pytorch 实现查看网络中的参数
Jan 06 Python
python可以用哪些数据库
Jun 22 Python
python如何查看安装了的模块
Jun 23 Python
Python大批量搜索引擎图像爬虫工具详解
Nov 16 Python
在Python中如何使用yield
Jun 07 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调用Linux的命令行执行文件压缩命令
2013/01/27 PHP
php获取从百度搜索进入网站的关键词的详细代码
2014/01/08 PHP
PHP读取CURL模拟登录时生成Cookie文件的方法
2014/11/04 PHP
浅谈PHP中的数据传输CURL
2016/09/06 PHP
php实现将二维关联数组转换成字符串的方法详解
2017/07/31 PHP
PHP删除数组中指定值的元素常用方法实例分析【4种方法】
2018/08/21 PHP
浅析AngularJS中的指令
2016/03/20 Javascript
JS遍历页面所有对象属性及实现方法
2016/08/01 Javascript
AngularJS表单和输入验证实例
2016/11/02 Javascript
jquery中$.fn和图片滚动效果实现的必备知识总结
2017/04/21 jQuery
jQueryMobile之窗体长内容的缺陷与解决方法实例分析
2017/09/20 jQuery
JavaScript累加、迭代、穷举、递归等常用算法实例小结
2018/05/08 Javascript
使用淘宝镜像cnpm安装Vue.js的图文教程
2018/05/17 Javascript
element vue Array数组和Map对象的添加与删除操作
2018/11/14 Javascript
学习 Vue.js 遇到的那些坑
2021/02/02 Vue.js
[06:07]辉夜杯现场观众互动 “比谁远送显示器”
2015/12/26 DOTA
Python实现可设置持续运行时间、线程数及时间间隔的多线程异步post请求功能
2018/01/11 Python
详解python校验SQL脚本命名规则
2019/03/22 Python
Python批量生成幻影坦克图片实例代码
2019/06/04 Python
linux环境下安装python虚拟环境及注意事项
2020/01/07 Python
Python字符编码转码之GBK,UTF8互转
2020/02/09 Python
Python3 Click模块的使用方法详解
2020/02/12 Python
matplotlib quiver箭图绘制案例
2020/04/17 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
2020/06/24 Python
css3实现二维码扫描特效的示例
2020/10/29 HTML / CSS
IE9下html5初试小刀
2010/09/21 HTML / CSS
武汉世纪畅想数字传播有限公司 .NET笔试题
2015/06/13 面试题
MYSQL基础面试题
2012/05/13 面试题
年终考核实施方案
2014/05/26 职场文书
优秀共产党员演讲稿
2014/09/04 职场文书
文明礼仪倡议书
2015/04/28 职场文书
幼师自荐信范文(2016推荐篇)
2016/01/28 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书
导游词之沈阳植物园
2019/11/30 职场文书
详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类
2022/04/08 Java/Android
基于Android10渲染Surface的创建过程
2022/08/14 Java/Android