Python_变量的作用域
2015-12-10 01:31
609 查看
目录
目录软件系统
变量的作用域
高级语言对数据类型的使用过程
作用域的产生
作用域的类型
Llocal局部作用域
Eenclosing嵌套作用域
Gglobal全局作用域
Bbuilt-in内置作用域
变量名解析LEGB法则
实例说明
对变量的引用
对变量的修改
global关键字
nonlocal关键字
最后
软件系统
系统Ubuntu 14.04
软件
Python 2.7.3
IPython 4.0.0
变量的作用域
在Python程序中创建、改变、查找变量名时,都是在一个保存变量名的空间中进行,我们称之为命名空间,也被称之为作用域。Python的作用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即Python变量的作用域由变量所在源代码中的位置决定。高级语言对数据类型的使用过程
一般的高级语言在使用变量时,都会有下面4个过程。当然在不同的语言中也会有着区别。1. 声明变量:让编辑器知道有这一个变量的存在
2. 定义变量:为不同数据类型的变量分配内存空间
3. 初始化:赋值,填充分配好的内存空间
4. 引用:通过引用对象(变量名)来调用内存对象(内存数据)
作用域的产生
就作用域而言,Python与C有着很大的区别,在Python中并不是所有的语句块中都会产生作用域。只有当变量在Module(模块)、Class(类)、def(函数)中定义的时候,才会有作用域的概念。In [19]: %pycat testScopt.py #!/usr/bin/env python def func(): variable = 100 print variable print variable NameError: name 'variable' is not defined
在作用域中定义的变量,一般只在作用域中有效。
注意:在if-elif-else、for-else、while、try-except\try-finally等关键字的语句块中并不会产成作用域。
In [15]: if True: ....: variable = 100 ....: print variable ....: print "******" ....: print variable ....: 100 ****** 100 #变量variable在if语句块内或外都表示同一个变量
作用域的类型
在Python中,使用一个变量时并不严格要求需要预先声明它,但是在真正使用它之前,它必须被绑定到某个内存对象(被定义、赋值);这种变量名的绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量。L(local)局部作用域
局部变量:包含在def关键字定义的语句块中,即在函数中定义的变量。每当函数被调用时都会创建一个新的局部作用域。Python中也有递归,即自己调用自己,每次调用都会创建一个新的局部命名空间。在函数内部的变量声明,除非特别的声明为全局变量,否则均默认为局部变量。有些情况需要在函数内部定义全局变量,这时可以使用global关键字来声明变量的作用域为全局。注意:如果需要在函数内部对全局变量赋值,需要在函数内部通过global语句声明该变量为全局变量。
E(enclosing)嵌套作用域
E也包含在def关键字中,E和L是相对的,E相对于更上层的函数而言也是L。与L的区别在于,对一个函数而言,L是定义在此函数内部的局部作用域,而E是定义在此函数的上一层父级函数的局部作用域。主要是为了实现Python的闭包,而增加的实现。G(global)全局作用域
即在模块层次中定义的变量,每一个模块都是一个全局作用域。也就是说,在模块文件顶层声明的变量具有全局作用域,从外部开来,模块的全局变量就是一个模块对象的属性。注意:全局作用域的作用范围仅限于单个模块文件内
B(built-in)内置作用域
系统内固定模块里定义的变量,如预定义在__builtin__ 模块内的变量。变量名解析LEGB法则
搜索变量名的优先级:局部作用域 > 嵌套作用域 > 全局作用域 > 内置作用域LEGB法则:
当在函数中使用未确定的变量名时,Python会按照优先级依次搜索4个作用域,以此来确定该变量名的意义。首先搜索局部作用域(L),之后是上一层嵌套结构中def或lambda函数的嵌套作用域(E),之后是全局作用域(G),最后是内置作用域(B)。按这个查找原则,在第一处找到的地方停止。如果没有找到,则会出发NameError错误。
一个LEGB的例子:
#!/usr/bin/env python #conding:utf8 globalVar = 100 #G def test_scope(): enclosingVar = 200 #E def func(): localVar = 300 #L print __name__ #B
实例说明
对变量的引用
在不同作用域中可以存在相同的变量名,当出现这种情况的时候,对LEGB法则的理解就显得非常重要了,否则就会有只能知其然而不知其所以然的感觉。实例1:
def func(): variable = 300 print variable variable = 100 func() print variable In [11]: %run testScopt.py 300 #优先搜索函数func()内的局部变量 100
实例2:
In [29]: %pycat testScopt.py #!/usr/bin/env python #conding:utf8 def test_scopt(): variable = 200 print variable def func(): print variable #这里的变量variable在E中绑定了内存对象200,为函数func()引入了一个新的变量 func() variable = 100 test_scopt() print variable In [30]: %run testScopt.py 200 200 #在函数func()中无法找到变量variable,升级到test_scopt()中寻找 100
例子3:
In [9]: %pycat testScopt.py #!/usr/bin/env python #conding:utf8 variable = 300 def test_scopt(): print variable #variable是test_scopt()的局部变量,但是在打印时并没有绑定内存对象。 variable = 200 test_scopt() print variable UnboundLocalError: local variable 'variable' referenced before assignment
上面的例子会报出错误,因为在执行程序时的预编译能够在test_scopt()中找到局部变量variable(对variable进行了赋值)。在局部作用域找到了变量名,所以不会升级到嵌套作用域去寻找。但是在使用print语句将变量variable打印时,局部变量variable并有没绑定到一个内存对象(没有定义和初始化,即没有赋值)。本质上还是Python调用变量时遵循的LEGB法则和Python解析器的编译原理,决定了这个错误的发生。
注意:为什么在这个例子中触发的错误是UnboundLocalError而不是NameError:name ‘variable’ is not defined。因为变量variable不在全局作用域。Python中的模块代码在执行之前,并不会经过预编译,但是模块内的函数体代码在运行前会经过预编译,因此不管变量名的绑定发生在作用域的那个位置,都能被编译器知道。Python虽然是一个静态作用域语言,但变量名查找是动态发生的,直到在程序运行时,才会发现作用域方面的问题。
例子4:
In [2]: %pycat testScopt.py #!/usr/bin/env python #conding:utf8 variable = 300 def test_scopt(): print variable #没有在局部作用域找到变量名,会升级到嵌套作用域寻找,并引入一个新的变量到局部作用域(将局部变量variable赋值为300)。 # variable = 200 test_scopt() print variable In [3]: %run testScopt.py 300 300
比较例子3和4能够更好的理解LEGB的过程。
对变量的修改
一个non-L的变量相对于L而言,默认是只读而不能修改的。如果希望在L中修改定义在non-L的变量,为其绑定一个新的值,Python会认为是在当前的L中引入一个新的变量(即便内外两个变量重名,但却有着不同的意义)。即在当前的L中,如果直接使用non-L中的变量,那么这个变量是只读的,不能被修改,否则会在L中引入一个同名的新变量。这是对上述几个例子的另一种方式的理解。注意:而且在L中对新变量的修改不会影响到non-L的。当你希望在L中修改non-L中的变量时,可以使用global、nonlocal关键字。
In [18]: %pycat testScopt.py #!/usr/bin/env python #conding:utf8 variable = 100 def test_scopt(): variable = 200 #在L中引入一个新变量,覆盖non-L中的变量 print variable test_scopt() print variable In [19]: %run testScopt.py 200 100
global关键字
希望在L中修改G中的变量。In [57]: %pycat test.py spam = 99 def tester(): def nested(): global spam print('current=',spam) spam = 200 return nested tester()() print spam In [58]: %run test.py ('current=', 99) 200
注意:tester()()表示会自动调用函数tester()的返回值,且此返回值必须为可调用类型,即存在__call__方法。返回一个函数,所以也会执行返回的函数体代码。
nonlocal关键字
在L中修改E中的变量。这是Python3.x增加的新特性,在python2.x中还是无法使用。def outer(): count = 10 def inner(): nonlocal count count = 20 print(count) inner() print(count) outer() #20 #20
最后
在Python中,类定义所引入的作用域对于类的成员函数是不可见的,所以在Python中,成员函数想要引用类体定义的变量,必须通过关键字self或者类名来引用它。这一知识要点,等我们下一篇再继续学习。Jmilk
相关文章推荐
- PyCharm_汉化包_编译器字体和背景怎么设置?_怎么添加多个python解释器?
- python 函数 字符串读入问题
- python 操作mysql数据库
- python使用SQL语句操作数据库中文乱码的解决
- WxPython学习
- python 自省1
- Python读取UTF-8编码文件并使用命令行执行时输出结果的问题
- 读完了简明Python教程(a bite of Python)
- Python第三方库使用——splinter
- python脚本编程:批量复制或删除文件
- python:类
- Python——迭代器和解析(3)
- Python exec,assert,lambda
- python学习第六课 --常用模块
- 用Python实现FTP暴力破解
- Python爬虫简单的demo
- python中struct模块及packet和unpacket
- python 与hadoop之pyhdfs的使用
- Wing IDE 5 for Python 安装及破解方法
- PYTHON 3.1 快速导览 – 内建字节数组型态 (BYTEARRAY)