Python概述
综述
- 语言的具体实现可能发生改变、其他实现可能使用不同方式
- 在语言的参考文档中加入过多细节实现很危险
Python实现
python只是一种语言,其具体解释器实现有很多种
CPython:C语言实现,最原始版本
- 通常就被称为Python,其他实现区分时才强调为CPython
- 新语言特性通常较早出现
Jython:Java实现
- 将Python代码编译为Java字节码
- 可以左线Java应用的脚本语言、创建需要Java类库支持的 应用
- 在JVM上运行
Python for .NET:实际上使用CPython实现,但是属于.NET 托管应用,可以引入.NET类库
IronPython:.NET实现
- 生成IL的完全Python实现,将Python代码直接编译为.NET 程序集
PyPy:RPython(Python语言子集)实现
- JIT编译器,执行效率高于CPython
- 非栈式支持
- 允许方便修改解释器,鼓励对语言本身进行实验
- CPython是解释器实现版本,
cython
是将Python代码翻译为 C插件的项目/包
Notation说明
标注:词法、句法解析的描述使用修改过的BNF语法标注
1 | name ::= lc_letter(lc_letter | "_")* |
::=
:声明规则,左侧为规则名称|
:分隔可选项*
:前一项的零次、多次重复+
:前一项的一次、多次重复[]
:括起内容可选,即出现零次、一次()
:分组""
:固定字符串包含在引号内:空格仅用于分隔token
...
:三个点分割的本义字符表示在指定区间范围内的任意 单个字符<>
:对所定义符号的非常描述,在必要时用于说明“控制字符” 意图
- 每条规则通常为一行,多个可选项规则可用
|
为界分为多行 - 词法定义:作用域输入源中的单独字符
- 句法定义:作用于词法分析生成的token stream
约定
- 实例方法:定义在类命名空间中、未因访问而绑定函数
- 绑定方法:已绑定实例方法
- 静态方法
- 类方法
- [类]实例:类实例化所得对象
- 对象:泛指所有python对象,包括类、实例
Global Intepretor Lock
全局内存锁:GIL,任何python字节码执行前必须获得的解释器锁
- 在任何时刻,只能有一个线程处于工作状态
- 避免多个线程同时操作变量导致内存泄漏、错误释放
优势
GIL实现简单,只需要管理一把解释器锁就能保证线程内存安全
- 当然GIL只能保证引用计数正确,避免由此导致内存问题
- 还需要原子操作、对象锁避免并发更新问题
GIL单线程情况下性能更好、稳定,若通过给所有对象引用计数 加锁来实现线程安全
- 容易出现死锁
- 性能下降很多
方便兼容C遗留库,这也是python得以发展的原因
- 很多python需要的C库扩展要求线程安全的内存管理
影响
Python线程是真正的操作系统线程
- 在准备好之后必须获得一把共享锁才能运行
- 每个线程都会在执行一定机器指令和后切换到无锁状态, 暂停运行
- 事实上程序在开始时已经在运行“主线程”
- 解释器检查线程切换频率
sys.getcheckinterval()
Python线程无法在多核CPU间分配,对CPU-Bound程序基本没有 提升效果,对于IO-Bound的程序性能仍然有巨大帮助
解决方案
多进程
- 进程分支:
os.fork
- 派生进程:
multiprocessing.Process
、concurrent.futures
- 进程分支:
C语言库封装线程:
ctypes
、cython
- C扩展形式实现任务线程可在python虚拟机作用域外运行 可以并行运行任意数量线程
- 在运行时释放GIL、结束后继续运行python代码时重新获取 GIL,真正实现独立运行
使用其他版本Python解释器:只有原始Python版本CPython使用 GIL实现
- Jython
- IronPython
- PyPy
Python最高层级组件
完整的Python程序
完整的python程序会在最小初始化环境中被执行
- 所有内置、标准模块均可用,但均处于未初始化状态
- 只有
sys
、builtins
、__main__
已经初始化 __main__
模块为完整程序的执行提供局部、全局命名空间
完整程序可通过三种形式传递给解释器
-c
命令行选项传递字符串- 文件作为第一个命令行参数
- 标准输入
- 若文件、标准输入是tty设备,解释器进入交互模式,否则 将文件当作完整程序执行
解释器也可以通过交互模式被发起调用
- 每次读取执行一条语句,语句会在
__main__
命名空间中 被执行 - 初始环境同完整程序
- 每次读取执行一条语句,语句会在
输入类型
文件输入
文件输入:从非交互式文件读取的输入,具有相同形式
1 | file_input ::= (NEWLINE|statement)* |
适合以下几种情况
- 解析完整的python程序(从文件、字符串)
- 解析模块
- 解析传递给
exec()
函数的字符串
交互式输入
交互式输入:从tty设备读取输入
1 | interactive_input ::= [stmt_list] NEWLINE | compound_stmt NEWLINE |
- 注意
- 交互模式中(最高层级)复合语句后必须带有空行,帮助 解释器确定输入的结束
表达式输入
表达式输入
1 | eval_input ::= expression_list NEWLINE* |
eval
被用于表达式输入- 忽略开头空白