4. 执行模型¶
4.1. 程序的结构¶
A Python program is constructed from code blocks.
A block is a piece of Python program text that is executed as a unit.
The following are blocks: a module, a function body, and a class definition.
Each command typed interactively is a block. A script file (a file given as
standard input to the interpreter or specified as a command line argument to the
interpreter) is a code block. A script command (a command specified on the
interpreter command line with the ‘-c’ option) is a code block. The string
argument passed to the built-in functions eval()
and exec()
is a
code block.
代码块在 执行帧 中被执行。 一个帧会包含某些管理信息(用于调试)并决定代码块执行完成后应前往何处以及如何继续执行。
4.2. 命名与绑定¶
4.2.1. 名称的绑定¶
名称 用于指代对象。 名称是通过名称绑定操作来引入的。
The following constructs bind names: formal parameters to functions,
import
statements, class and function definitions (these bind the
class or function name in the defining block), and targets that are identifiers
if occurring in an assignment, for
loop header, or after
as
in a with
statement or except
clause.
The import
statement
of the form from ... import *
binds all names defined in the imported
module, except those beginning with an underscore. This form may only be used
at the module level.
del
语句的目标也被视作一种绑定(虽然其实际语义为解除名称绑定)。
每条赋值或导入语句均发生于类或函数内部定义的代码块中,或是发生于模块层级(即最高层级的代码块)。
如果名称绑定在一个代码块中,则为该代码块的局部变量,除非声明为 nonlocal
或 global
。 如果名称绑定在模块层级,则为全局变量。 (模块代码块的变量既为局部变量又为全局变量。) 如果变量在一个代码块中被使用但不是在其中定义,则为 自由变量。
每个在程序文本中出现的名称是指由以下名称解析规则所建立的对该名称的 绑定。
4.2.2. 名称的解析¶
作用域 定义了一个代码块中名称的可见性。 如果代码块中定义了一个局部变量,则其作用域包含该代码块。 如果定义发生于函数代码块中,则其作用域会扩展到该函数所包含的任何代码块,除非有某个被包含代码块引入了对该名称的不同绑定。
当一个名称在代码块中被使用时,会由包含它的最近作用域来解析。 对一个代码块可见的所有这种作用域的集合称为该代码块的 环境。
当一个名称完全找不到时,将会引发 NameError
异常。 如果当前作用域为函数作用域,且该名称指向一个局部变量,而此变量在该名称被使用的时候尚未绑定到特定值,将会引发 UnboundLocalError
异常。 UnboundLocalError
为 NameError
的一个子类。
如果一个代码块内的任何位置发生名称绑定操作,则代码块内所有对该名称的使用会被认为是对当前代码块的引用。 当一个名称在其被绑定前就在代码块内被使用时则会导致错误。 这个一个很微妙的规则。 Python 缺少声明语法,并允许名称绑定操作发生于代码块内的任何位置。 一个代码块的局部变量可通过在整个代码块文本中扫描名称绑定操作来确定。
If the global
statement occurs within a block, all uses of the name
specified in the statement refer to the binding of that name in the top-level
namespace. Names are resolved in the top-level namespace by searching the
global namespace, i.e. the namespace of the module containing the code block,
and the builtins namespace, the namespace of the module builtins
. The
global namespace is searched first. If the name is not found there, the
builtins namespace is searched. The global
statement must precede
all uses of the name.
global
语句与同一代码块中名称绑定具有相同的作用域。 如果一个自由变量的最近包含作用域中有一条 global 语句,则该自由变量也会被当作是全局变量。
nonlocal
语句会使得相应的名称指向之前在最近包含函数作用域中绑定的变量。 如果指定名称不存在于任何包含函数作用域中则将在编译时引发 SyntaxError
。
模块的作用域会在模块第一次被导入时自动创建。 一个脚本的主模块总是被命名为 __main__
。
类定义代码块以及传给 exec()
和 eval()
的参数是名称解析上下文中的特殊情况。 类定义是可能使用并定义名称的可执行语句。 这些引用遵循正常的名称解析规则,例外之处在于未绑定的局部变量将会在全局命名空间中查找。 类定义的命名空间会成为该类的属性字典。 在类代码块中定义的名称的作用域会被限制在类代码块中;它不会扩展到方法的代码块中 – 这也包括推导式和生成器表达式,因为它们都是使用函数作用域实现的。 这意味着以下代码将会失败:
class A:
a = 42
b = list(a + i for i in range(10))
4.2.3. 内置命名空间和受限的执行¶
The builtins namespace associated with the execution of a code block is actually
found by looking up the name __builtins__
in its global namespace; this
should be a dictionary or a module (in the latter case the module’s dictionary
is used). By default, when in the __main__
module, __builtins__
is
the built-in module builtins
; when in any other module,
__builtins__
is an alias for the dictionary of the builtins
module
itself. __builtins__
can be set to a user-created dictionary to create a
weak form of restricted execution.
4.3. 异常¶
异常是中断代码块的正常控制流程以便处理错误或其他异常条件的一种方式。 异常会在错误被检测到的位置 引发,它可以被当前包围代码块或是任何直接或间接发起调用发生错误的代码块的其他代码块所 处理。
Python 解析器会在检测到运行时错误(例如零作为被除数)的时候引发异常。 Python 程序也可以通过 raise
语句显式地引发异常。 异常处理是通过 try
… except
语句来指定的。 该语句的 finally
子句可被用来指定清理代码,它并不处理异常,而是无论之前的代码是否发生异常都会被执行。
Python 的错误处理采用的是“终止”模型:异常处理器可以找出发生了什么问题,并在外层继续执行,但它不能修复错误的根源并重试失败的操作(除非通过从顶层重新进入出错的代码片段)。
When an exception is not handled at all, the interpreter terminates execution of
the program, or returns to its interactive main loop. In either case, it prints
a stack backtrace, except when the exception is SystemExit
.
异常是通过类实例来标识的。 except
子句会依据实例的类来选择:它必须引用实例的类或是其所属的基类。 实例可通过处理器被接收,并可携带有关异常条件的附加信息。
注解
异常消息不是 Python API 的组成部分。 其内容可能在 Python 升级到新版本时不经警告地发生改变,不应该被需要在多版本解释器中运行的代码所依赖。
另请参看 The try statement 小节中对 try
语句的描述以及 The raise statement 小节中对 raise
语句的描述。
备注
[1] | 出现这样的限制是由于通过这些操作执行的代码在模块被编译的时候并不可用。 |