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下使用Txt2Html实现网页过滤代理的教程
Apr 11 Python
python写入xml文件的方法
May 08 Python
一个基于flask的web应用诞生 用户注册功能开发(5)
Apr 11 Python
对numpy中布尔型数组的处理方法详解
Apr 17 Python
python3+PyQt5+Qt Designer实现扩展对话框
Apr 20 Python
完美解决Pycharm无法导入包的问题 Unresolved reference
May 18 Python
python中从str中提取元素到list以及将list转换为str的方法
Jun 26 Python
如何在python字符串中输入纯粹的{}
Aug 22 Python
Python中GeoJson和bokeh-1的使用讲解
Jan 03 Python
Python 2/3下处理cjk编码的zip文件的方法
Apr 26 Python
教你一步步利用python实现贪吃蛇游戏
Jun 27 Python
详解Matplotlib绘图之属性设置
Aug 23 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在字符断点处截断文字的实现代码
2011/04/21 PHP
ThinkPHP3.1的Widget新用法
2014/06/19 PHP
php中的curl_multi系列函数使用例子
2014/07/29 PHP
PHP实现动态删除XML数据的方法示例
2018/03/30 PHP
js自执行函数的几种不同写法的比较
2012/08/16 Javascript
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
2013/01/23 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
2014/08/14 Javascript
javascript关于继承的用法汇总
2014/12/20 Javascript
JS实现点击按钮获取页面高度的方法
2015/11/02 Javascript
js如何实现淡入淡出效果
2020/11/18 Javascript
浅谈使用MVC模式进行JavaScript程序开发
2015/11/10 Javascript
jquery心形点赞关注效果的简单实现
2016/11/14 Javascript
js制作可以延时消失的菜单
2017/01/13 Javascript
js图片延迟加载(Lazyload)三种实现方式
2017/03/01 Javascript
jQuery中的deferred使用方法
2017/03/27 jQuery
JS匹配日期和时间的正则表达式示例
2017/05/12 Javascript
微信小程序日历弹窗选择器代码实例
2019/05/09 Javascript
[04:12]第二届DOTA2亚洲邀请赛选手传记-Newbee.Sccc
2017/04/03 DOTA
python服务器与android客户端socket通信实例
2014/11/12 Python
对python实现合并两个排序链表的方法详解
2019/01/23 Python
PyCharm+Qt Designer+PyUIC安装配置教程详解
2019/06/13 Python
python多进程下的生产者和消费者模型
2020/05/07 Python
使用Keras画神经网络准确性图教程
2020/06/15 Python
Python 利用Entrez库筛选下载PubMed文献摘要的示例
2020/11/24 Python
美国批发供应商:Kole Imports
2019/04/10 全球购物
C#笔试题和英文面试题
2013/02/07 面试题
大四毕业生学习总结的自我评价
2013/10/31 职场文书
运动会解说词200字
2014/02/06 职场文书
工程类专业自荐信范文
2014/03/09 职场文书
大一新生学期自我评价
2014/04/09 职场文书
社区爱国卫生月活动总结
2014/06/30 职场文书
寒假安全保证书
2015/02/28 职场文书
法院个人总结
2015/03/03 职场文书
地道战观后感
2015/06/04 职场文书
大学文艺委员竞选稿
2015/11/19 职场文书
优胜劣汰,强者为王——读《鲁滨逊漂流记》有感
2019/08/15 职场文书