Python內部執行過程


一、編譯過程概述

  當我們執行Python代碼的時候,在Python解釋器用四個過程“拆解”我們的代碼,最終被CPU執行返回給用戶。

  首先當用戶鍵入代碼交給Python處理的時候會先進行詞法分析,例如用戶鍵入關鍵字或者當輸入關鍵字有誤時,都會被詞法分析所觸發,不正確的代碼將不會被執行。

  下一步Python會進行語法分析,例如當"for i in test:"中,test后面的冒號如果被寫為其他符號,代碼依舊不會被執行。

  下面進入最關鍵的過程,在執行Python前,Python會生成.pyc文件,這個文件就是字節碼,如果我們不小心修改了字節碼,Python下次重新編譯該程序時會和其上次生成的字節碼文件進行比較,如果不匹配則會將被修改過的字節碼文件進行覆蓋,以確保每次編譯后字節碼的准確性。

  那么什么是字節碼?字節碼在Python虛擬機程序里對應的是PyCodeObject對象。.pyc文件是字節碼在磁盤上的表現形式。簡單來說就是在編譯代碼的過程中,首先會將代碼中的函數、類等對象分類處理,然后生成字節碼文件。有了字節碼文件,CPU可以直接識別字節碼文件進行處理,接着Python就可執行了。

二、過程圖解

三、編譯字節碼

  Python中有一個內置函數compile(),可以將源文件編譯成codeobject,首先看這個函數的說明:

  compile(...) compile(source, filename, mode[, flags[, dont_inherit]]) -> code object

  參數1:源文件的內容字符串

  參數2:源文件名稱

  參數3:exec-編譯module,single-編譯一個聲明,eval-編譯一個表達式 一般使用前三個參數就夠了

  使用示例:

#src_file.py
#some function
def f(d=0):
    c=1 
    print "hello"
a=9
b=8
f()

>>> a=open('src_file.py','r').read()    #命令行模式中打開源文件進行編譯
>>> co=compile(a,'src_file','exec')
>>> type(co)
<type 'code'>    #編譯出了codeobject對象

四、codeobject對象的屬性

  codeobject有哪些變量,接上節的內容分析一下:

>>> print co.co_names    #所有的符號名稱
('f', 'a', 'b')

>>> print co.co_name    #模塊名、函數名、類名
<module>

>>> print co.co_consts    #常量集合、函數f和兩個int常量a,b,d
(0, <code object f at 0xb7273b18, file "src_file", line 2>, 9, 8, None)

>>> print co.co_consts[1].co_varnames    #可以看到f函數也是一個codeobject,打印f中的局部變量
('c',)

>>> print co.co_code    #字節碼指令
dZdZdZedS

>>> print co.co_consts[1].co_firstlineno    #代碼塊在文件中的起始行號
2

>>> print co.co_stacksize    #代碼棧大小
2

>>> print co.co_filename    #文件名
src_file    #模塊名、函數名、類名

  codeobject的co_code代表了字節碼,這個字節碼有什么含義?我們可以使用dis模塊進行python的反編譯:

import dis
dis.dis(co)
>>> output
 2        0 LOAD_CONST               0 (0)
          3 LOAD_CONST               1 (<code object f at 0xb7273b18, file "src_file", line 2>)
          6 MAKE_FUNCTION            1
          9 STORE_NAME               0 (f)
 5        12 LOAD_CONST              2 (9)
          15 STORE_NAME              1 (a)

 6        18 LOAD_CONST              3 (8)
          21 STORE_NAME              2 (b)

 7        24 LOAD_NAME               0 (f)
          27 CALL_FUNCTION           0
          30 POP_TOP             
          31 LOAD_CONST              4 (None)
          34 RETURN_VALUE

  從反編譯的結果來看,python字節碼其實是模仿的x86的匯編,將代碼編譯成一條一條的指令交給一個虛擬的cpu去執行。

  • 第一列:行號
  • 第二列:指令在代碼塊中的偏移量
  • 第三列:指令
  • 第四列:操作數
  • 第五列:操作數說明


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM