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与js)两种实现
Feb 21 Python
Python基础教程之浅拷贝和深拷贝实例详解
Jul 15 Python
python 递归遍历文件夹,并打印满足条件的文件路径实例
Aug 30 Python
flask中使用蓝图将路由分开写在不同文件实例解析
Jan 19 Python
python dataframe常见操作方法:实现取行、列、切片、统计特征值
Jun 09 Python
Python socket套接字实现C/S模式远程命令执行功能案例
Jul 06 Python
利用pandas进行大文件计数处理的方法
Jul 25 Python
详解windows python3.7安装numpy问题的解决方法
Aug 13 Python
python实现将文件夹内的每张图片批量分割成多张
Jul 22 Python
python 画出使用分类器得到的决策边界
Aug 21 Python
TensorFlow-gpu和opencv安装详细教程
Jun 30 Python
浅谈anaconda python 版本对应关系
Oct 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
全国FM电台频率大全 - 1 北京市
2020/03/11 无线电
php 下载保存文件保存到本地的两种实现方法
2013/08/12 PHP
PHP 只允许指定IP访问(允许*号通配符过滤IP)
2014/07/08 PHP
ThinkPHP模板中数组循环实例
2014/10/30 PHP
PHP正则验证Email的方法
2015/06/15 PHP
PHP-CGI远程代码执行漏洞分析与防范
2017/05/07 PHP
Aster vs KG BO3 第二场2.18
2021/03/10 DOTA
基于jquery异步传输json数据格式实例代码
2013/11/23 Javascript
js 通过html()及text()方法获取并设置p标签的显示值
2014/05/14 Javascript
js如何判断用户是否是用微信浏览器
2014/06/05 Javascript
分享20个提升网站界面体验的jQuery插件
2014/12/15 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
学习JavaScript设计模式(多态)
2015/11/25 Javascript
javascript HTML5文件上传FileReader API
2020/03/27 Javascript
js跨域资源共享 基础篇
2016/07/02 Javascript
JavaScript日期工具类DateUtils定义与用法示例
2018/09/03 Javascript
vue添加axios,并且指定baseurl的方法
2018/09/19 Javascript
Javascript中弹窗confirm与prompt的区别
2018/10/26 Javascript
微信小程序的授权实现过程解析
2019/08/02 Javascript
JavaScript canvas绘制折线图
2020/02/18 Javascript
VueJS实现用户管理系统
2020/05/29 Javascript
Python3+django2.0+apache2+ubuntu14部署网站上线的方法
2018/07/07 Python
Python eval的常见错误封装及利用原理详解
2019/03/26 Python
Python Pandas对缺失值的处理方法
2019/09/27 Python
Python判断三段线能否构成三角形的代码
2020/04/12 Python
详解tensorflow2.x版本无法调用gpu的一种解决方法
2020/05/25 Python
python 输入字符串生成所有有效的IP地址(LeetCode 93号题)
2020/10/15 Python
香港礼品网站:GiftU eshop
2017/09/01 全球购物
优秀的毕业生的自我评价
2013/12/12 职场文书
新闻编辑专业毕业自荐书范文
2014/02/05 职场文书
年终总结会议主持词
2014/03/17 职场文书
爱心捐书活动总结
2014/07/05 职场文书
乡镇党委书记第三阶段个人整改措施
2014/09/16 职场文书
党的群众路线教育实践活动心得体会(医院)
2014/11/03 职场文书
安娜卡列尼娜观后感
2015/06/11 职场文书
Mysql MVCC机制原理详解
2021/04/20 MySQL