01. 前言
Python程序的代码是如何组织的,在代码完成编写后,又是如何运行的,它其中的原理是怎么回事,大家对这些问题一定很感兴趣。
接下来,兔子先生带着大家一探究竟。
02. Python的总体架构
从顶层设计上来看,Python可以分为三大部分:
- 代码文件
File Groups
- 包括模块、库及用户自定义的模块。 - 解释器
Interpreter
- 又称Python虚拟机,对代码分析理解,翻译成字节流,并运行这些字节代码。 - 运行环境
Runtime Env
- 包括运行时的对象、基础类型结构、内存分配器和实时的运行状态信息。
其中,最左边的python的库,模块以及用户自定义的模块,都依赖于python解释器来实现,而python解释器主要包括扫描器,分词器,编译器和代码生成四部分,我们写一个python文件之后,由python解释器执行,其大致执行过程如下:
1、扫描器扫描python文件,将扫描结果发给分词器;
2、在扫描过程中识别出文件中的对象,类型和结构(注:在python中类型和结构都是对象);
3、分词器将结果发给编译器,编译器在此时生成相应对象同时给对象分配内存空间;
4、编译之后将代码生成,进行内存管理并处理当前状态。
5、对象、类型、结构体、内存管理以及当前状态构成了python极其复杂的runtime运行时。
还有,很多人会有疑问,python是动态语言,内存到底是如何管理的,初来乍到,我也不太明白,由于python的各种历史原因,python的内存处理和线程管理非常复杂,打开源码看看,如果出现类似object_new这样的东西,那么他的内存就是用C++中的new来开辟的,如果是object_malloc这样的东西,则表示内存是用C中的malloc来实现的。
python属于脱管型的语言,内存不需要我们手动处理,方便了很多,其实,python在底层是用自动引用计数器来实现的,python中创建小对象时,往往直接在内存池中创建,而大对象则是使用new/malloc从内存中再创建一个。针对并不复杂的对象关系时,比如只有一个对象时,python是不会运行链路检测的,而如果对象很多,过系又很复杂,就会有一个链路检测,以防出现循环引用和死循环的问题,当释放内存时,则遵守自动引用计数的规则,非常了不起。
参考链接
https://www.cnblogs.com/skyfree/p/3834030.html
03. File Groups
File Groups就是咱们的代码,在Python的代码的编写过程中,会包含自己编写的代码模块、依赖核心的模块、第三方模块和库文件(Linux下是so库,而Windows下面则是dll库)
比如下面一段代码:
from datetime import date
now = date.today()
import requests
r = requests.get('https://www.xtuz.net')
其中 datetime
就是核心模块, requests
则属于第三方模块,这段代码本身就属于用户的自定义代码模块了。
04. Interpreter
Scanner
负责词法分析的工作,将代码一行一行切分为 token,Parser
则负责语法分析,将 Token 组织为抽象语法树,Compiler
则将语法树转化为指令集合的字节码流,最后由 Code Evaluator
来执行这些字节码。
下图是.pyc文件内容,即字节码流。
05. Runtime Env
Object
和 Type Structure
分别是程序在运行过程中生成的对象和Python中的自带内建对象,如int、List、dict等。
而 Memory Allocator
则负责申请创建对象需要的内存,本质就是封装了 C 语言里面的 malloc()
函数。
Current State
负责维护运行时的各类状态信息,以便在程序执行过程中如果发生状态变化(正常态和异常态)时,仍然能正常运行。
更多内容
原文来自兔子先生网站:https://www.xtuz.net/detail-130.html