我想分享一些非常酷的東西我一直在和你學習Python字節碼,包括我如何添加對嵌套的支援函數,但我的印刷工說我需要將其控制在500 字以內。
這是一個假期週,他聳聳肩。 你希望我做什麼?
不包含程式碼片段,我討價還價了。
好吧,他讓出。
你知道我們為什麼要使用字節碼嗎?
我只是操作印刷機,不過我相信你。
很公平。讓我們開始吧。
為什麼我們先使用字節碼
Memphis,我用 Rust 寫的 Python 解釋器,有兩個執行引擎。兩者都不能運行所有程式碼,但都可以運行部分程式碼。
我的treewalk 解釋器 是您在不知道自己在做什麼的情況下建造的。 ?♂️ 將輸入的 Python 程式碼標記,產生抽象語法樹 (AST),然後遍歷樹並評估每個節點。表達式傳回值和語句修改符號表,符號表實作為一系列遵守 Python 作用域規則的作用域。只要記住簡單的肺炎 LEGB:局部、封閉、全域、內建。
我的字節碼虛擬機是如果你不知道自己在做什麼但想像你一樣行事時你會建構的。還有? ♂️。對於這個引擎,令牌和 AST 的工作方式相同,但我們不是步行,而是衝刺。我們將 AST 編譯為中間表示(IR),以下稱為字節碼。然後,我們建立一個基於堆疊的虛擬機器 (VM),它在概念上類似於 CPU,按順序執行字節碼指令,但它完全由軟體實作。
(對於這兩種方法的完整指南,沒有漫無目的,《Crafting Interpreters》非常好。)
我們首先為什麼要這樣做?只要記住兩個 P:便攜性和性能。還記得在 2000 年代初期,沒有人會對 Java 字節碼的可移植性閉嘴嗎? 您只需要一個 JVM,就可以執行在任何機器上編譯的 Java 程式! 出於技術和行銷原因,Python 選擇不採用這種方法,但理論上同樣的原則適用。 (實際上,編譯步驟是不同的,我很遺憾打開了這罐蠕蟲。)
性能才是最重要的。編譯後的 IR 是一種更有效的表示形式,而不是在程式的生命週期內多次遍歷 AST。我們看到,由於避免了重複遍歷 AST 的開銷,效能得到了提高,而且其扁平結構通常會在運行時帶來更好的分支預測和快取局部性。
(如果你沒有電腦架構背景,我不會責怪你沒有考慮快取——哎呀,我的職業生涯是從這個行業開始的,我對緩存的考慮遠遠少於我對如何避免的考慮編寫同一行程式碼兩次。
嘿夥計,這是 500 字。我們需要加載框架並讓其撕裂。
已經? !您排除了程式碼片段嗎?
沒有程式碼片段,老兄。
好吧好吧。只剩下500多了。我保證。
上下文對於 Python 變數很重要大約一年前,在提交我的字節碼 VM 實作之前,我已經了解了很多:我可以定義 Python 函數和類,呼叫這些函數並實例化這些類別。我通過一些測試限制了這種行為。但我知道我的實現很混亂,在添加更多有趣的東西之前我需要重新審視基礎知識。現在是聖誕節週,我想添加一些有趣的東西。
考慮使用此程式碼片段來呼叫函數,並密切注意 TODO。
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<bytecode compileerror> { let mut opcodes = vec![]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let (_, index) = self.get_local_index(name); // TODO how does this know if it is a global or local index? this may not be the right // approach for calling a function opcodes.push(Opcode::Call(index)); Ok(opcodes) } </bytecode>你考慮好了嗎?我們將函數參數載入到堆疊上並“呼叫函數”。在字節碼中,所有名稱都會轉換為索引(因為在虛擬機器運行時索引存取速度更快),但我們實際上沒有辦法知道我們在這裡處理的是本機索引還是全域索引。
現在考慮改進版本。
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<bytecode compileerror> { let mut opcodes = vec![self.compile_load(name)]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let argc = opcodes.len() - 1; opcodes.push(Opcode::Call(argc)); Ok(opcodes) } </bytecode>感謝您考慮程式碼。
我們現在支援巢狀函數呼叫!發生了什麼變化?
- Call 操作碼現在採用多個位置參數,而不是函數的索引。這指示 VM 在呼叫函數之前從堆疊中彈出多少個參數。
- 將參數從堆疊中彈出後,
- 函數本身將留在堆疊上,而compile_load已經為我們處理了本地與全域範圍。
讓我們看看compile_load 做了什麼。
fn compile_load(&mut self, name: &str) -> Opcode { match self.ensure_context() { Context::Global => Opcode::LoadGlobal(self.get_or_set_nonlocal_index(name)), Context::Local => { // Check locals first if let Some(index) = self.get_local_index(name) { return Opcode::LoadFast(index); } // If not found locally, fall back to globals Opcode::LoadGlobal(self.get_or_set_nonlocal_index(name)) } } }這裡有幾個關鍵的行動原則:
- 我們根據當前上下文進行匹配。遵循 Python 語義,我們可以認為 Context::Global 位於任何模組的頂層(而不僅僅是腳本的入口點),而 Context::Local 位於任何區塊內(即函數定義或類別定義)。
- 我們現在區分本地索引和非本地索引。 (因為我瘋狂地試圖破解索引0 在不同地方所指的內容,所以我引入了類型化整數。LocalIndex 和NonlocalIndex 為其他非類型化無符號整數提供類型安全。我將來可能會寫這個!)
- 我們可以在字節碼編譯時判斷是否存在具有給定名稱的局部變量,如果不存在,則在運行時我們將搜尋全域變數。這說明了 Python 內建的動態性:只要在函數執行時變數存在於該模組的全域範圍內,它的值就可以在執行時間解析。然而,這種動態解析度會帶來效能損失。雖然局部變數查找已最佳化為使用堆疊索引,但全域查找需要搜尋全域命名空間字典,速度較慢。該字典是名稱到物件的映射,而物件本身可能存在於堆上。誰知道有句話「放眼全球,行動本地」。實際上指的是 Python 作用域?
varname 中有什麼?
今天我要留給您的最後一件事是看看這些變數名稱是如何映射的。在下面的程式碼片段中,您會注意到在 code.varnames 中找到本機索引,在 code.names 中找到非本地索引。兩者都存在於 CodeObject 上,其中包含 Python 字節碼塊的元數據,包括其變數和名稱映射。
fn compile_function_call( &mut self, name: &str, args: &ParsedArguments) ) -> Result<bytecode compileerror> { let mut opcodes = vec![]; // We push the args onto the stack in reverse call order so that we will pop // them off in call order. for arg in args.args.iter().rev() { opcodes.extend(self.compile_expr(arg)?); } let (_, index) = self.get_local_index(name); // TODO how does this know if it is a global or local index? this may not be the right // approach for calling a function opcodes.push(Opcode::Call(index)); Ok(opcodes) } </bytecode>
varnames 和 name 之間的差異折磨了我好幾個星期(CPython 稱這些為 co_varnames 和 co_names),但它實際上相當簡單。 varnames 保存給定範圍內所有局部變數的變數名稱,names 保存所有非局部變數的變數名稱。
一旦我們正確追蹤這一點,其他一切都會正常工作。在運行時,VM 會看到 LOAD_GLOBAL 或 LOAD_FAST,並知道分別查看全域命名空間字典或本機堆疊。
老兄!古騰堡先生打電話說我們不能再按了。
好的!美好的!我得到它!我們發貨吧。 ?
孟菲斯的下一步是什麼?
噓!印刷工不知道我在寫結論,所以我會簡短地說。
透過固定的變數作用域和函數調用,我逐漸將注意力轉向堆疊追蹤和非同步支援等功能。如果您喜歡深入了解字節碼或對構建自己的解釋器有疑問,我很樂意聽取您的意見 - 發表評論!
訂閱並節省[無任何]
如果您想將更多類似的貼文直接發送到您的收件匣,您可以在這裡訂閱!
跟我一起工作
我指導軟體工程師在一個有時有些愚蠢的支持性環境中應對技術挑戰和職業發展。如果您有興趣,可以在這裡預約課程。
其他地方
除了指導之外,我還寫了我在自營職業和晚期診斷自閉症方面的經驗。更少的程式碼和相同數量的笑話。
- 湖效應咖啡,第 2 章 - 來自 Scratch dot org
以上是我如何在 Python 字節碼中添加對嵌套函數的支持的詳細內容。更多資訊請關注PHP中文網其他相關文章!

toAppendElementStoApythonList,usetheappend()方法forsingleements,Extend()formultiplelements,andinsert()forspecificpositions.1)useeAppend()foraddingoneOnelementAttheend.2)useextendTheEnd.2)useextendexendExendEnd(

TocreateaPythonlist,usesquarebrackets[]andseparateitemswithcommas.1)Listsaredynamicandcanholdmixeddatatypes.2)Useappend(),remove(),andslicingformanipulation.3)Listcomprehensionsareefficientforcreatinglists.4)Becautiouswithlistreferences;usecopy()orsl

金融、科研、医疗和AI等领域中,高效存储和处理数值数据至关重要。1)在金融中,使用内存映射文件和NumPy库可显著提升数据处理速度。2)科研领域,HDF5文件优化数据存储和检索。3)医疗中,数据库优化技术如索引和分区提高数据查询性能。4)AI中,数据分片和分布式训练加速模型训练。通过选择适当的工具和技术,并权衡存储与处理速度之间的trade-off,可以显著提升系统性能和可扩展性。

pythonarraysarecreatedusiseThearrayModule,notbuilt-Inlikelists.1)importThearrayModule.2)指定tefifythetypecode,例如,'i'forineizewithvalues.arreaysofferbettermemoremorefferbettermemoryfforhomogeNogeNogeNogeNogeNogeNogeNATATABUTESFELLESSFRESSIFERSTEMIFICETISTHANANLISTS。

除了shebang線,還有多種方法可以指定Python解釋器:1.直接使用命令行中的python命令;2.使用批處理文件或shell腳本;3.使用構建工具如Make或CMake;4.使用任務運行器如Invoke。每個方法都有其優缺點,選擇適合項目需求的方法很重要。

ForhandlinglargedatasetsinPython,useNumPyarraysforbetterperformance.1)NumPyarraysarememory-efficientandfasterfornumericaloperations.2)Avoidunnecessarytypeconversions.3)Leveragevectorizationforreducedtimecomplexity.4)Managememoryusagewithefficientdata

Inpython,ListSusedynamicMemoryAllocationWithOver-Asalose,而alenumpyArraySallaySallocateFixedMemory.1)listssallocatemoremoremoremorythanneededinentientary上,respizeTized.2)numpyarsallaysallaysallocateAllocateAllocateAlcocateExactMemoryForements,OfferingPrediCtableSageButlessemageButlesseflextlessibility。

Inpython,YouCansspecthedatatAtatatPeyFelemereModeRernSpant.1)Usenpynernrump.1)Usenpynyp.dloatp.dloatp.ploatm64,formor professisconsiscontrolatatypes。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver Mac版
視覺化網頁開發工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

Atom編輯器mac版下載
最受歡迎的的開源編輯器