在Python中,对象是经过名字进行关联和引用的。Python经过名字绑定操做来引入名字。html
Python中的所谓的代码块就是一段做为执行单元的程序。好比:模块、函数、类定义。在交互式环境中输入的命令也是代码块的一种。一个Python脚本文件也是一个代码块。还有就是,当咱们在命令行上使用-c
选项指定的命令也是一个代码块。传递给内建函数eval()和exec()的字符串参数也是代码块的一种。python
代码块是以执行帧的方式被执行的,一个执行帧包含了一些管理信息,能够用于调试。执行帧还会在执行完当前的代码块之后指定在何处,以怎样的方式执行接下来的代码。shell
Python中的做用域定义了名字在代码块中的可见性。若是在代码块中定义了一个局部变量,那么这个局部变量的做用域就是所在的这个代码块。若是这个定义发生在函数体内,则这个变量的做用域就扩展到包含在这个函数中的任何代码块中,可是,若是包含在这个函数中的一个代码块中,一样的名字被绑定到了不一样的对象上,那么外面的名字将不能被扩展到这个代码块中。函数
def out_func(): #a的做用域在out_func这个函数中 a = 0 b = 0 def in_func(): #a的做用域从out_func扩展到了in_func中,由于in_func这个代码块包含在out_func中 print(a) #out_func函数中的b不能扩展到in_func中,由于在in_func中,b从新绑定到了不一样的对象上,因此在out_func中的b的做用域不能扩展到in_func中。 b = 1
在Python中,定义在类代码块中名字只能在类中可见,而且类中的名字的做用域不能扩展到类中的方法中。若是在类定义中出现了生成器表达式和列表展开,那么类中的名字也不能扩展到这些表达式中,由于列表展开和生成器表达式的实现都是使用函数做用域的。ui
class C: a = 0 # 在列表表达式中,a会由于未定义而抛出NameError异常 b = list(a + i for i in range(10)) def method(self): #因为定义在类中的名字不能扩展到方法中,因此下面的语句是错误的,会抛出a未定义的NameError异常 print(a)
当在一个代码块中使用一个名字的时候,会对最近的外围做用域进行解析,以查找这个名字。全部的这些在当前代码块中可见的做用域的集合,称为
当前的代码块的环境。命令行
若是一个名字绑定到一个代码块中,除非这个名字声明为nonlocal(nonlocal声明的做用是:使得变量在外围做用域中,在全局做用域以前被解析),不然这个名字就是这个代码块的局部变量。若是一个名字被绑定到模块级别,则这个名字的做用域是全局的,这个变量是全局变量(模块中的变量,对于模块而言是局部变量,而对于模块中的代码块而言,则是全局变量)。若是一个名字在一个代码块中使用,可是不是在这个代码块中被定义的,则这个变量就是一个自由变量。调试
若是在进行名字查找的时候,名字没有被找到,则会抛出一个 NameError 异常,若是名字引用的是一个局部变量,可是这个名字尚未被绑定到这个局部变量,则会抛出一个 UnboundLocalError 异常(UnboundLocalError 是 NameError的子类)。code
发生名字绑定的行为主要有:htm
from ... import *
语句会将被导入的模块中的全部能够被导入的名字进行绑定操做在Python中,名字绑定的一些规则,会致使在使用名字的时候,出现不能理解的错误,特别是对于有C、C++ 和 Java经验的用户。对象
在Python中,名字绑定操做不管发生在当前块的 任何 位置,在这个代码块中对这个名字的引用都会使用在当前块中绑定的对象。那么,问题就来了,若是咱们在名字绑定操做发生以前对这个名字进行了引用,那么就会出现错误,抛出 UnboundLocalError 异常。
>>> a = 10 >>> def function(): print(a) a = 20 # a的绑定操做发生在print以前 >>> function() Traceback (most recent call last): File "<pyshell#5>", line 1, in <module> function() File "<pyshell#4>", line 2, in function print(a) UnboundLocalError: local variable 'a' referenced before assignment
在Python中,代码块中的局部变量能够经过扫描整个代码块来得到绑定的名字,因此在上面的代码中,a这个名字在执行print的时候经过对代码块的扫描已经被找到,可是名字a的绑定操做却尚未发生,因此出现了错误。
在上面的代码中,若是咱们须要外面定义的全局变量a,则可使用global 语句进行声明。
>>> a = 10 >>> def function(): global a print(a) a = 20 #这里并不引入新的名字,而是将全局变量a绑定到20上 >>> function() 10 >>> a 20
global 语句的做用是,使得后面对经过这条语句声明的对象的引用,使用的是顶层名字空间中的名字。在顶层名字空间中,包含了全局名字空间和内建名字空间,全局名字空间会首先被搜索,若是没有找到,会对内建名字空间进行搜索。global 语句必须出如今名字使用以前。
若是在外围做用域中的自由变量包含了一个global声明,则这个自由变量被认为是全局的。
在查找内建名字空间的时候,会访问当前代码块的全局名字空间中的 __builtins__名字,这个名字引用的是一个名字字典或者是一个模块。在 __main__ 模块中, __builtins__ 的引用是内建模块 builtins,然而,若是是在其余模块中, __builtins__ 引用的是 builtins 模块的名字字典。
注意:
CPython的实现中,不能手动修改 __builtins__ 这个变量,若是须要覆盖这个内建名字空间中的名字,须要导入 builtins 模块,而后修改这个模块中相应的属性。