python基础教程之执行模型
4. 执行模型¶
4.1. 命名与绑定¶
变量名 指定对象. 变量通过名称绑定完成. 每一个变量通过绑定 之后供程序调用.
一个块是一段单独python代码.块包括: 一个模块,一段方法体,一个类. 每个可交互的命令的是一个块. 一个脚本文件 (可以被解释器当做标准输出或命令行参数)是一段代码块. 一个脚本命令(一个指定了 ‘-c‘ 选项的命令行)是一段代码块. 需要传入字符参数的内建方法 eval() 和 exec() 也是代码块.
一个代码块就是一个 执行片段. 一个片段包含一些信息 (用于调试) 且决定在何时并以何种方式继续执行下一段代码.
scope 定义了在一个块内变量的可见性. 如果在一个块内定义的变量,他的scope就是这个块.如果定义在一个方法块中, scope为所有调用此方法的块,除了那些给这个变量重新绑定成其它对象的块之外. 变量在一个类块中的scope为当前的类; 但这并非说明可以在类中任意使用. 也就是说下面这段代码执行会失败:
class A:
a = 42
b = list(a + i for i in range(10))
当一个代码块中使用一个变量名时 它只能用于最近的scope. 这些对于代码块的可见范围被称做代码块的 环境.
如果一个变量名被绑定到一个块内,那么它对于这个块来说就是一个局部变量除非将其声明为nonlocal. 如果一个变量名被绑定在一个模块的范围内,那么它是一个全局变量. (定义在模块中的变量既是本地变量也是全局变量.) 如果一个变量在代码块中只使用但未定义,那么他是一个 自由变量.
在“变量名“根本找不到时,就会抛出 NameError 异常. 如果变量名引用了一个未绑定的局部变量,就会抛出 UnboundLocalError 异常。 UnboundLocalError 是 NameError的一个子类。
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. 这种形式只可以在模块级别使用。
A target occurring in a del statement is also considered bound for this purpose (though the actual semantics are to unbind the name).
每个赋值和导入语句出现在类或函数定义的代码块中或者出现在模块级别(顶级代码块)。
如果在代码块的任意地方出现名称绑定操作,那么代码块中该名称的所有使用将被当做对当前代码块的引用。当名称在一个代码块中绑定之前使用时将导致错误。这个规则是微妙的。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 statement must precede all uses of the name.
与执行的代码块相关联的内建命名空间实际上是通过查找它的全局命名空间中的__builtins__名称找到的;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__可以被设置成一个用户创建的字典以创建一个严格执行的弱形式。
CPython实现细节: Users should not touch __builtins__; it is strictly an implementation detail. Users wanting to override values in the builtins namespace should import the builtins module and modify its attributes appropriately.
模块的命名空间在模块第一次导入时自动创建。脚本的主模块总是被称为__main__。
global语句具有和同一个代码块中名称绑定操作相同的定义域。如果包含自由变量的最内层定义域包含一条global语句,那么这个自由变量被认为是一个全局变量。
类定义是一条可以使用和定义名称的可执行语句。这些引用遵循名称解析的正常规则。类定义的命名空间变成类的属性字典。类定义域中定义的名称在方法中不可见。
4.1.1. 与动态功能的交互¶
当与包含自由变量的嵌套定义域联合使用的时候,有几种Python语句是非法的情况。
如果变量在一个包含它的定义域中被引用,那么删除它的名称是非法的。在编译的时刻将会报告一个错误。
The eval() and exec() functions do not have access to the full environment for resolving names. 名称可以在调用者的局部和全局命名空间中解析。自由变量不是在包含它们的最内层命名空间中解析,而是在全局命名空间中。[1] The exec() and eval() functions have optional arguments to override the global and local namespace. 如果只指明一个命名空间,则两个命名空间都会使用它。
4.2. 异常¶
异常是指代码片段中,可以捕获错误或者其他意外情况的流程中断异常在错误检测到的点引发;它可以通过包围它的代码块或者直接或间接调用发生错误的代码块的代码块处理。
Python解释器在检测到运行时错误(例如除0)时会引发一个异常。Python还可以通过raise语句显示地引发异常。Exception handlers are specified with the try … except statement. 这种语句的finally子句可以用来指定清除代码,它不处理异常,而是在前面的代码中无论有没有出现异常都会执行。
Python uses the “termination” model of error handling: an exception handler can find out what happened and continue execution at an outer level, but it cannot repair the cause of the error and retry the failing operation (except by re-entering the offending piece of code from the top).
当一个异常没有被任何处理,那么解释器会终止程序的执行或者返回到其交互式的主循环。In either case, it prints a stack backtrace, except when the exception is SystemExit.
异常通过类的实例标识。The except clause is selected depending on the class of the instance: it must reference the class of the instance or a base class thereof. 实例可以通过处理器接收并且可以带有异常条件的额外信息。
注意
Exception messages are not part of the Python API. 它们的内容可能随着Python 版本不断地改变而没有警告,在多种不同版本的解释器下运行的代码不应该依赖这些内容。
另请参考try语句小节中的try语句和raise语句小节中的raise语句。
脚注
[1] | 出现这种限制是因为通过这些操作执行的代码在模块编译的时候不可以访问。 |