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 字典(dict)遍历的四种方法性能测试报告
Jun 25 Python
详解在Python中处理异常的教程
May 24 Python
Python模拟自动存取款机的查询、存取款、修改密码等操作
Sep 02 Python
python中实现控制小数点位数的方法
Jan 24 Python
Python同步遍历多个列表的示例
Feb 19 Python
Python获取数据库数据并保存在excel表格中的方法
Jun 12 Python
python+selenium 点击单选框-radio的实现方法
Sep 03 Python
python构建指数平滑预测模型示例
Nov 21 Python
django API 中接口的互相调用实例
Apr 01 Python
浅谈Pycharm的项目文件名是红色的原因及解决方式
Jun 01 Python
python正则表达式的懒惰匹配和贪婪匹配说明
Jul 13 Python
python中requests模拟登录的三种方式(携带cookie/session进行请求网站)
Nov 17 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
ThinkPHP模板判断输出Present标签用法详解
2014/06/30 PHP
ThinkPHP提交表单时默认自动转义的解决方法
2014/11/25 PHP
PHP浮点数的一个常见问题
2016/03/10 PHP
CodeIgniter连贯操作的底层原理分析
2016/05/17 PHP
关于php几种字符串连接的效率比较(详解)
2017/02/22 PHP
PHP析构函数destruct与垃圾回收机制的讲解
2019/03/22 PHP
编写高性能的JavaScript 脚本的加载与执行
2010/04/19 Javascript
js自定义事件代码说明
2011/01/31 Javascript
JS检测输入字符是否包含非法字符的示例代码
2014/02/11 Javascript
jquery无法设置checkbox选中即没有变成选中状态
2014/03/27 Javascript
深入浅析AngularJS和DataModel
2016/02/16 Javascript
jQuery实现鼠标经过购物车出现下拉框代码(推荐)
2016/07/21 Javascript
使用jquery判断一个元素是否含有一个指定的类(class)实例
2017/02/12 Javascript
React Native之prop-types进行属性确认详解
2017/12/19 Javascript
JavaScript中Object基础内部方法图
2018/02/05 Javascript
在vue中使用SockJS实现webSocket通信的过程
2018/08/29 Javascript
js中位运算的运用实例分析
2018/12/11 Javascript
JavaScript实现邮箱后缀提示功能的示例代码
2018/12/13 Javascript
使用apifm-wxapi模块中的问题及解决方法
2019/08/05 Javascript
Vuex的API文档说明详解
2020/02/05 Javascript
JavaScript实现多个物体同时运动
2020/03/12 Javascript
JavaScript或jQuery 获取option value值方法解析
2020/05/12 jQuery
从零学Python之入门(二)基本数据类型
2014/05/25 Python
Python3安装Pymongo详细步骤
2017/05/26 Python
Windows上使用Python增加或删除权限的方法
2018/04/24 Python
python连接mongodb密码认证实例
2018/10/16 Python
Python学习笔记之Django创建第一个数据库模型的方法
2019/08/07 Python
python如何实现单链表的反转
2020/02/10 Python
Python字典fromkeys()方法使用代码实例
2020/07/20 Python
详解python tcp编程
2020/08/24 Python
python利用后缀表达式实现计算器功能
2021/02/22 Python
HTML5自定义元素播放焦点图动画的实现
2019/09/25 HTML / CSS
旅游项目开发策划书
2014/01/18 职场文书
《小石潭记》教学反思
2014/02/13 职场文书
大学生应聘导游自荐信
2014/06/02 职场文书
文艺有韵味的诗句(生命类、亲情类...)
2019/07/11 职场文书