Python的底層內(nèi)存模型之模塊、類、對(duì)象的存儲(chǔ)與運(yùn)行機(jī)制
前言
這篇博客從內(nèi)存布局、對(duì)象存儲(chǔ)、屬性管理三個(gè)核心維度,總結(jié)匯總 Python 的底層內(nèi)存模型和運(yùn)行機(jī)制
一、先編譯,后解釋
Python 既非純編譯型也非純解釋型語言,其運(yùn)行流程可概括為:
源代碼(.py) → 編譯生成字節(jié)碼(.pyc) → Python虛擬機(jī)(PVM)解釋執(zhí)行字節(jié)碼 → 與操作系統(tǒng)交互
- 編譯階段:解釋器將源代碼轉(zhuǎn)為字節(jié)碼(中間代碼),并緩存到__pycache__目錄,重復(fù)運(yùn)行時(shí)直接加載字節(jié)碼提升效率;
- 執(zhí)行階段:Python 虛擬機(jī)(PVM)逐行解釋字節(jié)碼,翻譯成機(jī)器指令執(zhí)行;
- 核心特性:CPython 的 GIL(全局解釋器鎖)限制同一時(shí)刻僅一個(gè)線程執(zhí)行字節(jié)碼,這也是 Python 多線程在 CPU 密集型任務(wù)中效率不高的核心原因。
Python 無 Java 式嚴(yán)格的 “堆、棧、方法區(qū)” 物理劃分,但從開發(fā)者視角可簡化為兩大核心區(qū)域:
| 區(qū)域 | 核心作用 | 存儲(chǔ)內(nèi)容 |
|---|---|---|
| 棧幀區(qū) | 臨時(shí)存儲(chǔ)函數(shù)調(diào)用上下文 | 局部變量、參數(shù)的引用(地址) |
| 堆區(qū) | 存儲(chǔ)所有實(shí)際數(shù)據(jù) | 所有對(duì)象(實(shí)例、類、模塊、函數(shù)等) |
二、模塊對(duì)象:.py 文件的 “屬性容器”
當(dāng)我們導(dǎo)入模塊或運(yùn)行.py文件時(shí),Python 解釋器會(huì)為該文件創(chuàng)建一個(gè)模塊對(duì)象****(module 類型實(shí)例),這是模塊級(jí)內(nèi)容的核心載體。
- 模塊對(duì)象的核心特性
- 創(chuàng)建時(shí)機(jī):import模塊或運(yùn)行腳本時(shí)自動(dòng)創(chuàng)建,創(chuàng)建后緩存到sys.modules(字典,key 為模塊名,value 為模塊對(duì)象的引用地址);
- 存儲(chǔ)內(nèi)容:模塊的__dict__屬性是其核心,等價(jià)于全局命名空間(globals()返回的就是該字典),包含:
- 自定義內(nèi)容:全局變量、類、函數(shù);
- 內(nèi)置屬性:file(文件路徑)、name(模塊名)等;
- 特殊場(chǎng)景:直接運(yùn)行的腳本會(huì)被命名為__main__模塊,這也是if name == "main"的底層邏輯。
- __file__指向文件路徑
__file__并非代碼 “查找” 的結(jié)果,而是解釋器在創(chuàng)建模塊對(duì)象時(shí),主動(dòng)將文件路徑賦值給模塊對(duì)象的內(nèi)置屬性 —— 它是模塊對(duì)象的 “路徑標(biāo)簽”,而非運(yùn)行時(shí)動(dòng)態(tài)查找的結(jié)果。
三、包的加載
- python在加載模塊時(shí),會(huì)先加載模塊所在的包,當(dāng)包第一次被導(dǎo)入時(shí),Python 會(huì)執(zhí)行
__init__.py中的所有代碼,可以在這里做初始化操作(比如加載配置、初始化常量、檢查依賴等) - 當(dāng)我們執(zhí)行 import my_package 或 from my_package import utils 時(shí),Python 會(huì)按以下步驟把包 / 模塊加載成模塊對(duì)象(Module Object)
- 查找模塊 / 包的路徑,從sys.path中查找包
- 執(zhí)行其中的
__init__.py代碼,將該包內(nèi)的__init__.py模塊(python文件)構(gòu)建模塊對(duì)象,把__init__.py中定義的變量、導(dǎo)入的對(duì)象作為__init__.py模塊對(duì)象的屬性(__dict__字典中)
三、類對(duì)象與實(shí)例對(duì)象:屬性的分層存儲(chǔ)
類和實(shí)例對(duì)象是 Python 面向?qū)ο蟮暮诵?,二者的屬性存?chǔ)遵循 “分層管理” 原則,核心載體仍是__dict__字典(堆區(qū)存儲(chǔ))。
- 類對(duì)象:方法與類屬性的 “倉庫”
- 存儲(chǔ)邏輯:類對(duì)象(如class Person:定義的Person)作為模塊對(duì)象的屬性存在,其__dict__存儲(chǔ):
- 類屬性(如species = “Human”);
- 方法(本質(zhì)是函數(shù)對(duì)象,如say_hello);
- 繼承特性:類屬性查找會(huì)逐層向上遍歷父類的__dict__(如Person繼承object,會(huì)查找object.dict)。
- 實(shí)例對(duì)象:獨(dú)有屬性的 “專屬空間”
- 存儲(chǔ)邏輯:實(shí)例(如p = Person())存在堆區(qū),每個(gè)實(shí)例有獨(dú)立的__dict__,僅存儲(chǔ)實(shí)例獨(dú)有屬性(如self.name);
- 屬性查找優(yōu)先級(jí):實(shí)例訪問屬性時(shí),先查自身__dict__ → 查類對(duì)象__dict__ → 查父類__dict__ → 拋出AttributeError;

- sys.module 是堆區(qū)的一塊緩沖區(qū),是個(gè)字典,存儲(chǔ)所有module對(duì)象,key是模塊名、value是module對(duì)象的引用地址
- 每一個(gè)module對(duì)象也是通過__dict__ 字典存儲(chǔ)著該模塊的所有全局變量、類對(duì)象、實(shí)例對(duì)象,key: 屬性名(類名、對(duì)象名、方法名),value:類、對(duì)象、方法的引用地址
- sys.modules 本身是堆區(qū)的字典對(duì)象,地址固定;類對(duì)象、實(shí)例對(duì)象、模塊對(duì)象的__dict__也是通過起始地址的固定偏移量計(jì)算出來的。
- 編譯完模塊文件后,先在堆區(qū)分配地址,創(chuàng)建存儲(chǔ)當(dāng)前模塊的模塊對(duì)象,初始化其核心屬性(dict, file,name),然后將創(chuàng)建的當(dāng)前模塊對(duì)象地址存儲(chǔ)到 sys.module 字典緩沖區(qū)中,然后解釋器會(huì)將當(dāng)前模塊地址存儲(chǔ)到一個(gè)全局的 “模塊上下文” (模塊執(zhí)行幀,非棧幀),這個(gè)模塊上下文會(huì)貫穿程序執(zhí)行的始終,程序會(huì)實(shí)時(shí)從這個(gè)模塊執(zhí)行幀中拿到最近的模塊對(duì)象地址。
四、Python 內(nèi)存管理的核心原則
- 引用為王:Python 中所有變量賦值、屬性存儲(chǔ)都是 “引用傳遞”(存地址),而非 “值傳遞”(存數(shù)據(jù));
- 垃圾回收:堆區(qū)對(duì)象的生命周期由 “引用計(jì)數(shù)” 主導(dǎo)(計(jì)數(shù)為 0 則回收),分代回收補(bǔ)充處理循環(huán)引用;
- 分層查找:屬性訪問遵循 “實(shí)例→類→父類” 的優(yōu)先級(jí),模塊對(duì)象的__dict__是全局命名空間的核心;
- 緩存優(yōu)化:小整數(shù)(-5~256)、短字符串等常駐 “只讀數(shù)據(jù)區(qū)”(堆區(qū)子集),全局共享避免重復(fù)創(chuàng)建。
五、總結(jié)
Python 的內(nèi)存模型可概括為 “兩區(qū)域、三對(duì)象、一核心”:
- 兩區(qū)域:棧幀區(qū)存引用,堆區(qū)存所有對(duì)象;
- 三對(duì)象:模塊對(duì)象管理文件級(jí)內(nèi)容,類對(duì)象管理方法和類屬性,實(shí)例對(duì)象管理獨(dú)有屬性;
- 一核心:所有對(duì)象的屬性都基于__dict__字典(或優(yōu)化數(shù)組)存儲(chǔ),核心邏輯是 “引用 + 分層查找”。
到此這篇關(guān)于Python的底層內(nèi)存模型之模塊、類、對(duì)象的存儲(chǔ)與運(yùn)行機(jī)制的文章就介紹到這了,更多相關(guān)python內(nèi)存模型存儲(chǔ)與運(yùn)行機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用Python將動(dòng)態(tài)GIF圖片倒放播放的方法
GIF(Graphics Interchange Format) 是一種可以用來呈現(xiàn)動(dòng)畫效果的圖片格式,原理就是保存很多幀(Frame)靜態(tài)圖像,然后連續(xù)呈現(xiàn)。這篇文章主要介紹了用Python將動(dòng)態(tài)GIF圖片倒放播放的方法,需要的朋友可以參考下2016-11-11
Python調(diào)用百度api實(shí)現(xiàn)語音識(shí)別詳解
這篇文章主要介紹了Python通過調(diào)用百度api實(shí)現(xiàn)語音識(shí)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2021-12-12
Python標(biāo)準(zhǔn)庫uuid模塊(生成唯一標(biāo)識(shí))詳解
uuid通過Python標(biāo)準(zhǔn)庫的uuid模塊生成通用唯一ID(或“UUID”)的一種快速簡便的方法,下面這篇文章主要給大家介紹了關(guān)于Python標(biāo)準(zhǔn)庫uuid模塊(生成唯一標(biāo)識(shí))?的相關(guān)資料,需要的朋友可以參考下2022-05-05
python二維碼操作:對(duì)QRCode和MyQR入門詳解
今天小編就為大家分享一篇python二維碼操作:對(duì)QRCode和MyQR入門詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06
Python深度學(xué)習(xí)albumentations數(shù)據(jù)增強(qiáng)庫
下面開始albumenations的正式介紹,在這里我強(qiáng)烈建議英語基礎(chǔ)還好的讀者去官方網(wǎng)站跟著教程一步步學(xué)習(xí),而這里的內(nèi)容主要是我自己的一個(gè)總結(jié)以及方便英語能力較弱的讀者學(xué)習(xí)2021-09-09
python高并發(fā)異步服務(wù)器核心庫forkcore使用方法
這篇文章主要介紹了python高并發(fā)異步服務(wù)器核心庫forkcore的使用方法,大家參考使用吧2013-11-11
python標(biāo)識(shí)符命名規(guī)范原理解析
這篇文章主要介紹了python標(biāo)識(shí)符命名規(guī)范原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01

