Python的作用域

转自:http://www.cnblogs.com/frydsh/archive/2012/08/12/2602100.html

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函数返回所有的局部变量,但是不会返回嵌套作用域中的变量,实际上没有函数会返回嵌套作用域中的变量。

参考:

http://www.python.org/dev/peps/pep-0227/

http://beastie.cs.ua.edu/cs150/book/book_13.html

http://www-inst.eecs.berkeley.edu/~selfpace/cs9honline/Q2/scope.html

http://www.saltycrane.com/blog/2008/01/python-variable-scope-notes/

Python的作用域的更多相关文章

  1. 详解Python的作用域和命名空间

    最近在学习Python,不得不说,Python真的是一门很好用的语言.但是学习的过程中关于变量作用域(scope)的命名空间(namespace)的问题真的把我给搞懵了.在查阅了相关资料之后,觉得自己 ...

  2. python变量作用域

    [python变量作用域] 几个概念: python能够改变变量作用域的代码段是def.class.lamda. if/elif/else.try/except/finally.for/while 并 ...

  3. Python 变量作用域 LEGB (上)—— Local,Global,Builtin

    Python 变量作用域的规则是 LEGB LEGB含义解释:L —— Local(function):函数内的名字空间E —— Enclosing function locals:外部嵌套函数的名字 ...

  4. Python 变量作用域与函数

    Python 的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承.Py ...

  5. Python 变量作用域 LEGB (下)—— Enclosing function locals

    上篇:Python 变量作用域 LEGB (上)—— Local,Global,Builtin https://www.cnblogs.com/yvivid/p/python_LEGB_1.html ...

  6. [Python] 命名空间&作用域

    Python的类语句不会创建实例 类会创建命名空间,通过对象访问类的属性和方法 类不会创建作用域,对方法和属性的引用必须加以限定(如在方法中必须通过self引用实例的属性) class My1(): ...

  7. python的作用域、globals()-全局变量 和 locals()-局部变量

    在python中,函数会创建一个自己的作用域,也称为为命名空间.当我们在函数内部访问某个变量时,函数会优先在自己的命名空间中寻找. 我们自己定义的全局变量均在python内建的globals()函数中 ...

  8. Python函数作用域的查找顺序

    函数作用域的LEGB顺序 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.它们 ...

  9. Python 之作用域和名字空间

    作用域与名字空间 Python有一个核心概念是名字空间(namespace),namespace是一个name到object 的映射关系,Python有很多namespace,因此,在代码中如果碰到一 ...

随机推荐

  1. Android之自定义画图文字动画

    结构: BaseView: package com.caiduping.canvas; import android.content.Context; import android.graphics. ...

  2. centos6.5下逻辑卷操作

    1.将两块独立磁盘分别分区 2.创建物理卷-pvcreate 3.创建卷组 4.创建逻辑卷 5.格式化逻辑卷 6.扩展逻辑卷 7.缩小逻辑卷

  3. 第七篇、使用UIView的animateWithDuration方法制作简易动画

    import UIKit class LolitaCircleButton: UIButton { private var color: UIColor private var imageURL: S ...

  4. 第二十八篇、自定义的UITableViewCell上有图片需要显示,要求网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示图片缩略图

    1)SDWebImage会自动帮助开发者缓存图片(包括内存缓存,沙盒缓存),所以我们需要设置用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图. 2)许多 ...

  5. ASP.NET实现在线人员实时显示

    在最近的学习中,参考其他资源,做了一个简单的在线人员显示的功能,总结了一下,思路如下: 1.定义一个全局的内存来作为在线人员列表 2.通过实时判断用户Session值,来判断某个用户的登录或离线 3. ...

  6. OC1_类方法的内存管理

    // // Dog.h // OC1_类方法的内存管理 // // Created by zhangxueming on 15/6/19. // Copyright (c) 2015年 zhangxu ...

  7. css笔记--web端小于1px设计的处理方法

    HTML代码 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UT ...

  8. IE浏览器打开 「兼容性视图」

    有些IE上的网页控件需要打开兼容性视图才能使用,不知道是Javascript的原因,还是CSS的原因. 使用环境是用C语言配合boa服务器实现的CGI程序.

  9. Servlet、Filter 生命周期

    Servlet作为JavaEE必须掌握的内容,Struts2通过使用Filter的功能实现了一个MVC的框架.因此掌握这Servlet以及Filter的生命周期显得非常重要. 1. Servlet的生 ...

  10. DEV GridControl表格数据源为空在表格中间显示提醒字符

    private static void gv_CustomDrawEmptyForeground(object sender, DevExpress.XtraGrid.Views.Base.Custo ...