Python执行模型
综述
Code Blocks
代码块:作为一个单元执行的一段python文本,代码块构成python 程序
- 模块、函数体、类定义
- 交互式输入的每条命令
- 作为标准输入、命令行参数发送给解释器的脚本文件
- 脚本命令
- 传递给
eval()
、exec()
的字符串参数
- 代码块在执行帧中执行,执行帧包含某些用于调试的管理信息 并决定代码块执行完成后操作
Naming、Binding
Binding of Names
- 名称:用于指代对象,通过名称绑定操作引入
名称绑定方法
- 传递参数
import
语句from ... import *
会绑定被导入模块中定义的所有 公有名称(仅在模块层级上被使用)
- 类、函数定义
- 以标识符为目标的赋值
for
循环开头、with
和except
子句的as
之后del
语句的目标也被视为绑定,虽然实际语义为解除名称 绑定
变量类型
- 局部变量:绑定在代码块中的名称,且未声明为
nonlocal
、或global
- 全局变量:绑定在模块层级的名称
- 模块代码块中变量既为全局变量、也是局部变量
- 自由变量:在代码块中使用但未在其中定义的变量
- 局部变量:绑定在代码块中的名称,且未声明为
- 自由变量不同于闭包变量,函数闭包变量
__closure__
要求 自由变量来自于父函数作用域
Scope
作用域:定义了代码块中名称的可见性
名称的作用域包含
- 定义该变量代码块
- 定义变量代码块所包含的代码块 (除非被包含代码块中引入对该名称不同绑定)
名称作用域虽然包括定义变量代码块所包含的代码块
- 可以直接访问变量
- 但修改变量必须使用
global
、local
等声明
在代码块内任何位置进行名称绑定,则代码块内所有对该名称 的使用被认为是对代码块的引用
- python没有声明语法,则代码块中局部变量可通过,在整个 代码块文本中扫描名称绑定来确定
模块作用域在模块第一次被导入时创建
Resolution of Names
若名称在代码块中被使用,会由包含它的最近作用域来解析
若名称完全无法找到将
raise NameError
若当前作用域为函数作用域,且名称指向局部变量,若名称被 绑定值前被被使用将
raise UnboundLocalError
(UnboundLocalError
是NameError
子类)
- (代码块)环境:对代码块可见的所作用域集合
global
对
global
指定名称的使用是对最高层级命名空间中该名称 绑定的引用- 全局命名空间:包含代码块的模块命名空间
- 内置命名空间:
builtins
模块的命名空间
global
语句与同一代码块中名称绑定具有相同作用域- 若自由变量最近包含作用域中有
global
语句,其也会被 当作全局变量
- 若自由变量最近包含作用域中有
global
语句须在名称使用之前声明
nonlocal
nonlocal
使得相应名称指向最近包含函数作用域的中绑定的 变量指定名称不存在于任何包含函数作用域则
raise SyntaxError
内置命名空间
与代码块执行相关联的内置命名空间实际上是通过其在全局命名 空间中搜索名称
__builtins__
找到,一般是字典、模块 (此时使用模块的命名空间字典)默认情况下
__main__
模块中:__builtins__
为内置模块builtins
- 非
__main__
模块中:__buitlins__
是builtins
模块 自身的字典别名
动态特性
自由变量的名称解析
1
2
3
4
5
6i = 0
def f():
print(i)
i = 42
f()
# 打印`42`- 发生在运行时,而不是编译时
- 在全局命名空间中,而不是最近包含命名空间中
eval()
、exec()
eval()
、exec()
没有对完整环境的访问权限来解析名称- 有可选参数用于重载全局、局部命名空间
- 若只指定一个命名空间,则会同时作用于两者
类
类中名称解析遵守大部分情况下同普通规则,但 未绑定局部变将在全局命名空间中搜索
类定义的命名空间
__dict__
会成为类的属性字典类代码块中定义的名称的作用域会被限制在类代码块中,不会 扩展到方法代码块中,包括推导式、生成器表达式
1
2
3class A:
a = 42
b = list(a + i for i in range(10))
Exception
异常:中断代码块的正常控制流程以便处理错误、其他异常条件的 方式
在错误被检测到的位置引发
- 解释器检测到运行时错误时错误
raise
语句显式引发
可被当前包围代码块、任何直接或间接主调代码块捕获、处理
try...except
指定错误处理,finally
子句清理代码- 异常通过实例标识、根据器类型选择执行
except
子句
错误处理采用“终止”模型
- 异常处理器可以找出发生的问题,在外层继续执行
- 但不能修复错误的根源,并重试失败操作
- 异常完全未被处理时,解释器会终止程序执行、或返回交互
模式循环,并打印栈回溯信息,除非为
SystemExit
异常
异常实例可以携带关于异常状态的额外信息
- 异常信息不是python API一部分,内容可能在不同python 版本间不经警告的改变