Python学习之变量的做用域

学习地址:http://www.jianshu.com/p/17a9d8584530python

一、变量做用域LEGB

1.1变量的做用域

在Python程序中建立、改变、查找变量名时,都是在一个保存变量名的空间中进行,咱们称之为命名空间,也被称之为做用域。python的做用域是静态的,在源代码中变量名被赋值的位置决定了该变量能被访问的范围。即Python变量的做用域由变量所在源代码中的位置决定。闭包

1.2高级语言对数据类型的使用过程

通常的高级语言在使用变量时,都会有下面4个过程。固然在不一样的语言中也会有着区别。编辑器

  1. 声明变量:让编辑器知道有这一个变量的存在
  2. 定义变量:为不一样数据类型的变量分配内存空间
  3. 初始化:赋值,填充分配好的内存空间
  4. 引用:经过引用对象(变量名)来调用内存对象(内存数据)

1.3做用域的产生

就做用域而言,Python与C有着很大的区别,在Python中并非全部的语句块中都会产生做用域。只有当变量在Module(模块)、Class(类)、def(函数)中定义的时候,才会有做用域的概念。看下面的代码:函数

#!/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等关键字的语句块中并不会产成做用域。看下面的代码:ui

if True:
    variable = 100
    print (variable)
print ("******")
print (variable)

代码的输出为:spa

100
******
100

因此,能够看到,虽然是在if语句中定义的variable变量,可是在if语句外部仍然可以使用。code

1.4做用域的类型:

在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 模块内的变量。

1.5变量名解析LEGB法则

搜索变量名的优先级:局部做用域 > 嵌套做用域 > 全局做用域 > 内置做用域
LEGB法则: 当在函数中使用未肯定的变量名时,Python会按照优先级依次搜索4个做用域,以此来肯定该变量名的意义。首先搜索局部做用域(L),以后是上一层嵌套结构中def或lambda函数的嵌套做用域(E),以后是全局做用域(G),最后是内置做用域(B)。按这个查找原则,在第一处找到的地方中止。若是没有找到,则会出发NameError错误。

几个实例:

1.

def func():
    variable = 300
    print variable

variable = 100
func() #300
print variable  #100

2.

variable = 300
def test_scopt():
  print variable #variable是test_scopt()的局部变量,可是在打印时并无绑定内存对象。
  variable = 200 #由于这里,因此variable就变为了局部变量
test_scopt()
print variable
上面的例子会报出错误,由于在执行程序时的预编译可以在test_scopt()中找到局部变量variable(对variable进行了赋值)。在局部做用域找到了变量名,因此不会升级到嵌套做用域去寻找。可是在使用print语句将变量variable打印时,局部变量variable并有没绑定到一个内存对象(没有定义和初始化,即没有赋值)。本质上仍是Python调用变量时遵循的LEGB法则和Python解析器的编译原理,决定了这个错误的发生。因此,在调用一个变量以前,须要为该变量赋值(绑定一个内存对象)。
注意:为何在这个例子中触发的错误是UnboundLocalError而不是NameError:name ‘variable’ is not defined。由于变量variable不在全局做用域。 Python中的模块代码在执行以前,并不会通过预编译,可是模块内的函数体代码在运行前会通过预编译,所以无论变量名的绑定发生在做用域的那个位置,都能被编译器知道。Python虽然是一个静态做用域语言,但变量名查找是动态发生的,直到在程序运行时,才会发现做用域方面的问题
相关文章
相关标签/搜索