1.Python程序的執行過程html
Python解釋器(interpreter)在執行任何一個Python程序文件時,首先進行的動做都是先對文件中的Python源代碼進行編譯,編譯的主要結果是產生的一組Python的字節碼(byte code),而後將編譯的結果交給Python虛擬機(Virtual Machine),由虛擬機按照順序一條一條地執行字節碼,從而完成對Python程序的執行動做。java
對比java的執行:python
java: .java-->(javac)-->.class-->(java)-->結果linux
python: .py -->(編譯器)-->.pyc-->(虛擬機)-->結果vim
從上面可知:Python對源碼的編譯結果是產生的一個.pyc文件,這其實並不太準確。數組
如:閉包
~/code/py/dis/demo.pyapp
1 class A: 2 pass 3 def f(): 4 pass 5 a = A() 6 f()
執行:python demo.py,並無產生.pyc文件。ssh
分析以下:ide
對於Python編譯器來講,PyCodeObject對象是其真正的編譯結果,而pyc文件只是這個對象在硬盤上的表現形式。
在程序的運行期間,編譯結果存在於內存的PyCodeObject對象中;而運行結束後,這個編譯結果又被保存到pyc文件中。當下次運行相同的程序時,Python會根據pyc文件中記錄的編譯結果直接創建內存中PyCodeObject對象,而不用再次對源碼進行編譯了。
把py文件的編譯結果保存到pyc文件,最大的優勢在於在運行程序時,不須要對該源碼從新進行編譯。因此,須要編譯造成pyc文的應該是那些能夠重用的代碼。
對於僅僅運行一次的程序,保存其對於的pyc文件時沒有必要的。
若是程序要執行import導入模塊的操做,程序運行時會觸發pyc文件的生成(若是該模塊在PATH路徑下與之已有匹配的pyc文件,不需生成直接使用便可)。
2.Python源碼中的PyCodeObject
Include/code.h:
1 /* Bytecode object */ 2 typedef struct { 3 PyObject_HEAD 4 int co_argcount; /* #arguments, except *args */ 5 int co_kwonlyargcount; /* #keyword only arguments */ 6 int co_nlocals; /* #local variables */ 7 int co_stacksize; /* #entries needed for evaluation stack */ 8 int co_flags; /* CO_..., see below */ 9 PyObject *co_code; /* instruction opcodes */ 10 PyObject *co_consts; /* list (constants used) */ 11 PyObject *co_names; /* list of strings (names used) */ 12 PyObject *co_varnames; /* tuple of strings (local variable names) */ 13 PyObject *co_freevars; /* tuple of strings (free variable names) */ 14 PyObject *co_cellvars; /* tuple of strings (cell variable names) */ 15 /* The rest doesn't count for hash or comparisons */ 16 unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ 17 PyObject *co_filename; /* unicode (where it was loaded from) */ 18 PyObject *co_name; /* unicode (name, for reference) */ 19 int co_firstlineno; /* first source line number */ 20 PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See 21 Objects/lnotab_notes.txt for details. */ 22 void *co_zombieframe; /* for optimization only (see frameobject.c) */ 23 PyObject *co_weakreflist; /* to support weakrefs to code objects */ 24 } PyCodeObject;
在解釋PyCodeObject中各個域的含義以前,先說明一個概念--Code Block:
Python編譯器在對Python源碼進行編譯的時候,對代碼中的一個Code Block,會建立一個PyCodeObject對象與這段代碼對應。
如何肯定多少代碼算一個Code Block?
Python中肯定Code Block的規則:當進入一個新的名字空間或做用域時,就算進入了一個新的Code Block了。
即:一個名字空間對應一個Code Block,它會對應一個PyCodeObject。
如今暫且認爲名字空間就是符號的上下文環境,是名字到對象的映射。名字空間之後會詳述。
在Python中,類、函數和module都對應着一個獨立的名字空間,所以都會對應一個PyCodeObject對象。
例如:
~/code/py/dis/demo.py
1 class A: 2 pass 3 def f(): 4 pass 5 a = A() 6 f()
Python編譯器對demo.py源碼編譯以後,會建立3個PyCodeObject對象:第一個是對應整個demo.py文件表明的Code Block,第二個是對應Class A表明的Code Block,第三個是對應f表明的Code Block。
PyCodeObject中各個域的含義:
(1)co_argcount、co_kwonlyargcount
PEP 3102:http://www.python.org/dev/peps/pep-3102/
Keyword-only argument:在函數參數列表中,出如今*varargs以後的命名參數只能使用關鍵參數的形式調用。
函數調用是參數的賦值順序:位置參數-->關鍵字參數-->可變參數(*varargs)
co_argcount:CodeBlock中位置參數的個數,即:在調用時出現的位置參數的個數(不包含可變參數*varargs)。
co_kwonlyargcount:CodeBlock中的關鍵參數的個數,即在調用時是出如今可變參數(*varargs)以後的參數個數,可變參數以後的參數均是形式爲「keyvalue」的關鍵參數。
>>> def f1(a, b, c, *d, e, f): ... m = 1 ... pass ... >>> f1.__code__.co_argcount 3 >>> f1.__code__.co_kwonlyargcount 2
(2)co_nlocals:Code Block中的全部局部變量的個數,包括code block的參數(co_argcount+co_kwonlyargcount+可變參數個數)+code block內的局部變量
>>> f1.__code__.co_nlocals 7
7 = (3+2+1)+1
(3)co_stacksize:執行該段Code Block須要的棧空間數
>>> f1.__code__.co_stacksize 1
(4)co_code:Code Block編譯所得的字節碼指令序列
>>> f1.__code__.co_code b'd\x01\x00}\x06\x00d\x00\x00S'
(5)co_consts、co_names
co_consts:Code Block中的全部常量的元組
co_names:Code Block中的全部符號(名字)的元組
>>> f1.__code__.co_consts (None, 1) >>> f1.__code__.co_names ()
(6)co_filename、co_name
co_filename:Code Block所對應的的.py文件的完整路徑
co_name:Code Block的名字,,一般是函數名或類名
>>> f1.__code__.co_filename '<stdin>' >>> f1.__code__.co_name 'f1'
非交互式運行結果:
vim demo1.py
def f1(a, b, c, *d, e, f): m = 1 pass print(f1.__code__.co_filename) print(f1.__code__.co_name)
運行:
[root@lq dis]# python demo1.py demo1.py f1
(7)co_firstlineno:Code Block在對應的.py文件中的起始行
demo1.py
def f1(a, b, c, *d, e, f): m = 1 pass print(f1.__code__.co_firstlineno)
運行:
[root@lq dis]# python demo1.py 1
(8)co_varnames、co_freevars、co_cellvars
co_varnames:在本代碼段中被賦值,但沒有被內層代碼段引用的變量
co_freevars(freevars:自由變量):在本代碼段中被引用,在外層代碼段中被賦值的變量
co_cellvars(cellvars:被內層代碼所約束的變量):在本代碼段中被賦值,且被內層代碼段引用的變量
例1:簡單函數
vim demo1.py:
1 def f1(a, b, c, *d, e, f): 2 m = 1 3 pass 4 5 print('co_argcount :', f1.__code__.co_argcount) 6 print('co_kwonlyargcount :', f1.__code__.co_kwonlyargcount) 7 print('co_nlocals :', f1.__code__.co_nlocals) 8 print('co_stacksize :', f1.__code__.co_stacksize) 9 print('co_flags :', f1.__code__.co_flags) 10 print('co_code :', f1.__code__.co_code) 11 print('co_consts :', f1.__code__.co_consts) 12 print('co_names :', f1.__code__.co_names) 13 print('co_varnames :', f1.__code__.co_varnames) 14 print('co_freevars :', f1.__code__.co_freevars) 15 print('co_cellvars :', f1.__code__.co_cellvars) 16 print('co_filename :', f1.__code__.co_filename) 17 print('co_name :', f1.__code__.co_name) 18 print('co_firstlineno :', f1.__code__.co_firstlineno) 19 print('co_lnotab :', f1.__code__.co_lnotab)
運行:
[root@lq dis]# python demo1.py co_argcount : 3 co_kwonlyargcount : 2 co_nlocals : 7 co_stacksize : 1 co_flags : 71 co_code : b'd\x01\x00}\x06\x00d\x00\x00S' co_consts : (None, 1) co_names : () co_varnames : ('a', 'b', 'c', 'e', 'f', 'd', 'm') co_freevars : () co_cellvars : () co_filename : demo1.py co_name : f1 co_firstlineno : 1 co_lnotab : b'\x00\x01\x06\x01'
例2:嵌套函數
vim demo2.py
1 def f1(a, b, c, *d, e, f): 2 m = 1 3 def f2(): 4 n = m 5 print('f2-->co_argcount :', f2.__code__.co_argcount) 6 print('f2-->co_kwonlyargcount :', f2.__code__.co_kwonlyargcount) 7 print('f2-->co_nlocals :', f2.__code__.co_nlocals) 8 print('f2-->co_stacksize :', f2.__code__.co_stacksize) 9 print('f2-->co_flags :', f2.__code__.co_flags) 10 print('f2-->co_code :', f2.__code__.co_code) 11 print('f2-->co_consts :', f2.__code__.co_consts) 12 print('f2-->co_names :', f2.__code__.co_names) .co_varnames) 16 print('f2-->co_filename :', f2.__code__.co_filename) 17 print('f2-->co_name :', f2.__code__.co_name) 18 print('f2-->co_firstlineno :', f2.__code__.co_firstlineno) 19 print('f2-->co_lnotab :', f2.__code__.co_lnotab) 20 21 print('f1-->co_argcount :', f1.__code__.co_argcount) 22 print('f1-->co_kwonlyargcount :', f1.__code__.co_kwonlyargcount) 23 print('f1-->co_nlocals :', f1.__code__.co_nlocals) 24 print('f1-->co_stacksize :', f1.__code__.co_stacksize) 25 print('f1-->co_flags :', f1.__code__.co_flags) 26 print('f1-->co_code :', f1.__code__.co_code) 27 print('f1-->co_consts :', f1.__code__.co_consts) 28 print('f1-->co_names :', f1.__code__.co_names) .co_varnames) 32 print('f1-->co_filename :', f1.__code__.co_filename) 33 print('f1-->co_name :', f1.__code__.co_name) 34 print('f1-->co_firstlineno :', f1.__code__.co_firstlineno) 35 print('f1-->co_lnotab :', f1.__code__.co_lnotab) 36 print('=========================================================') 37 f1(1, 2, 3, 4, 5, 6, 7, e = 8, f = 9)
運行:
1 [root@lq dis]# python demo2.py 2 f1-->co_argcount : 3 3 f1-->co_kwonlyargcount : 2 4 f1-->co_nlocals : 7 5 f1-->co_stacksize : 3 6 f1-->co_flags : 7 7 f1-->co_code : b'd\x01\x00\x89\x00\x00\x87\x00\x00f\x01\x00d\x02\x00d\x03\x00\x86\x00\x00}\x06\x00t\x00\x00d\x04\x00|\x06\x00j\x01\x00j\x02\x00\x83\x02\x00\x01t\x00\x00d\x05\x00|\x06\x00j\x01\x00j\x03\x00\x83\x02\x00\x01t\x00\x00d\x06\x00|\x06\x00j\x01\x00j\x04\x00\x83\x02\x00\x01t\x00\x00d\x07\x00|\x06\x00j\x01\x00j\x05\x00\x83\x02\x00\x01t\x00\x00d\x08\x00|\x06\x00j\x01\x00j\x06\x00\x83\x02\x00\x01t\x00\x00d\t\x00|\x06\x00j\x01\x00j\x07\x00\x83\x02\x00\x01t\x00\x00d\n\x00|\x06\x00j\x01\x00j\x08\x00\x83\x02\x00\x01t\x00\x00d\x0b\x00|\x06\x00j\x01\x00j\t\x00\x83\x02\x00\x01t\x00\x00d\x0c\x00|\x06\x00j\x01\x00j\n\x00\x83\x02\x00\x01t\x00\x00d\r\x00|\x06\x00j\x01\x00j\x0b\x00\x83\x02\x00\x01t\x00\x00d\x0e\x00|\x06\x00j\x01\x00j\x0c\x00\x83\x02\x00\x01t\x00\x00d\x0f\x00|\x06\x00j\x01\x00j\r\x00\x83\x02\x00\x01t\x00\x00d\x10\x00|\x06\x00j\x01\x00j\x0e\x00\x83\x02\x00\x01t\x00\x00d\x11\x00|\x06\x00j\x01\x00j\x0f\x00\x83\x02\x00\x01t\x00\x00d\x12\x00|\x06\x00j\x01\x00j\x10\x00\x83\x02\x00\x01d\x00\x00S' 8 f1-->co_consts : (None, 1, <code object f2 at 0x7f5c2f036930, file "demo2.py", line 3>, 'f1.<locals>.f2', 'f2-->co_argcount :', 'f2-->co_kwonlyargcount :', 'f2-->co_nlocals :', 'f2-->co_stacksize :', 'f2-->co_flags :', 'f2-->co_code :', 'f2-->co_consts :', 'f2-->co_names :', 'f2-->co_varnames :', 'f2-->co_freevars :', 'f2-->co_cellvars :', 'f2-->co_filename :', 'f2-->co_name :', 'f2-->co_firstlineno :', 'f2-->co_lnotab :') 9 f1-->co_names : ('print', '__code__', 'co_argcount', 'co_kwonlyargcount', 'co_nlocals', 'co_stacksize', 'co_flags', 'co_code', 'co_consts', 'co_names', 'co_varnames', 'co_freevars', 'co_cellvars', 'co_filename', 'co_name', 'co_firstlineno', 'co_lnotab') ) 13 f1-->co_filename : demo2.py 14 f1-->co_name : f1 15 f1-->co_firstlineno : 1 16 f1-->co_lnotab : b'\x00\x01\x06\x01\x12\x02\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01\x13\x01' 17 ========================================================= 18 f2-->co_argcount : 0 19 f2-->co_kwonlyargcount : 0 20 f2-->co_nlocals : 1 21 f2-->co_stacksize : 1 22 f2-->co_flags : 19 23 f2-->co_code : b'\x88\x00\x00}\x00\x00d\x00\x00S' 24 f2-->co_consts : (None,) 25 f2-->co_names : () ,) 29 f2-->co_filename : demo2.py 30 f2-->co_name : f2 31 f2-->co_firstlineno : 3 32 f2-->co_lnotab : b'\x00\x01'
例3:閉包
vim demo3.py
1 def f1(a, b, c, *d, e, f): 2 m = 1 3 def f2(): 4 n = m 5 return f2 6 7 print('f1-->co_argcount :', f1.__code__.co_argcount) 8 print('f1-->co_kwonlyargcount :', f1.__code__.co_kwonlyargcount) 9 print('f1-->co_nlocals :', f1.__code__.co_nlocals) 10 print('f1-->co_stacksize :', f1.__code__.co_stacksize) 11 print('f1-->co_flags :', f1.__code__.co_flags) 12 print('f1-->co_code :', f1.__code__.co_code) 13 print('f1-->co_consts :', f1.__code__.co_consts) 14 print('f1-->co_names :', f1.__code__.co_names) .co_varnames) 18 print('f1-->co_filename :', f1.__code__.co_filename) 19 print('f1-->co_name :', f1.__code__.co_name) 20 print('f1-->co_firstlineno :', f1.__code__.co_firstlineno) 21 print('f1-->co_lnotab :', f1.__code__.co_lnotab) 22 print('=========================================================') 23 f3 = f1(1, 2, 3, 4, 5, 6, 7, e = 8, f = 9) 24 print('f3-->co_argcount :', f3.__code__.co_argcount) 25 print('f3-->co_kwonlyargcount :', f3.__code__.co_kwonlyargcount) 26 print('f3-->co_nlocals :', f3.__code__.co_nlocals) 27 print('f3-->co_stacksize :', f3.__code__.co_stacksize) 28 print('f3-->co_flags :', f3.__code__.co_flags) 29 print('f3-->co_code :', f3.__code__.co_code) 30 print('f3-->co_consts :', f3.__code__.co_consts) 31 print('f3-->co_names :', f3.__code__.co_names) 32 print('f3-->co_varnames :', f3.__code__.co_varnames) 33 print('f3-->co_freevars :', f3.__code__.co_freevars) 34 print('f3-->co_cellvars :', f3.__code__.co_cellvars) 35 print('f3-->co_filename :', f3.__code__.co_filename) 36 print('f3-->co_name :', f3.__code__.co_name) 37 print('f3-->co_firstlineno :', f3.__code__.co_firstlineno) 38 print('f3-->co_lnotab :', f3.__code__.co_lnotab)
運行:
1 [root@lq dis]# python demo3.py 2 f1-->co_argcount : 3 3 f1-->co_kwonlyargcount : 2 4 f1-->co_nlocals : 7 5 f1-->co_stacksize : 3 6 f1-->co_flags : 7 7 f1-->co_code : b'd\x01\x00\x89\x00\x00\x87\x00\x00f\x01\x00d\x02\x00d\x03\x00\x86\x00\x00}\x06\x00|\x06\x00S' 8 f1-->co_consts : (None, 1, <code object f2 at 0x7f010517e930, file "demo3.py", line 3>, 'f1.<locals>.f2') 9 f1-->co_names : () ) 13 f1-->co_filename : demo3.py 14 f1-->co_name : f1 15 f1-->co_firstlineno : 1 16 f1-->co_lnotab : b'\x00\x01\x06\x01\x12\x02' 17 ========================================================= 18 f3-->co_argcount : 0 19 f3-->co_kwonlyargcount : 0 20 f3-->co_nlocals : 1 21 f3-->co_stacksize : 1 22 f3-->co_flags : 19 23 f3-->co_code : b'\x88\x00\x00}\x00\x00d\x00\x00S' 24 f3-->co_consts : (None,) 25 f3-->co_names : () 26 f3-->co_varnames : ('n',) 27 f3-->co_freevars : ('m',) 28 f3-->co_cellvars : () 29 f3-->co_filename : demo3.py 30 f3-->co_name : f2 31 f3-->co_firstlineno : 3 32 f3-->co_lnotab : b'\x00\x01'
(9)co_lnotab:字節碼指令與.pyc文件中的source code行號的對於關係
Object/lnotab_notes.txt:
All about co_lnotab, the line number table.
Code objects store a field named co_lnotab. This is an array of unsigned bytes disguised as a Python string. It is used to map bytecode offsets to source code line #s for tracebacks and to identify line number boundaries for line tracing.
The array is conceptually a compressed list of (bytecode offset increment, line number increment) pairs. The details are important and delicate, best illustrated by example:
byte code offset source code line number
0 1
6 2
50 7
350 307
361 308
Instead of storing these numbers literally, we compress the list by storing only the increments from one row to the next.Conceptually, the stored list might look like:
0, 1, 6, 1, 44, 5, 300, 300, 11, 1
造成的數組:0, 1, (0+6), (1+1), (6+44), (2+5), (50+300), (7+300), (350+11), (307+1)
3.在Python中訪問PyCodeObject對象
以上的例子中已經有一個函數的屬性能夠訪問函數對應的PyCodeObject對象:__code__,函數的該屬性表示已經編譯函數體的Code Object。
在Python中,能夠經過code對象訪問PyCodeObject對象中的各個域。code對象是對C一級的PyCodeObject對象的一個簡單包裝。
經過內建函數compile能夠得到一個code對象。
例如:
demo.py:
class A: pass def f(): pass a = A() f()
交互式:
>>> source = open('./demo.py').read() >>> source 'class A:\n pass\ndef f():\n pass\na = A()\nf()\n' >>> co = compile(source, './demo.py', 'exec') >>> type(co) <class 'code'> >>> dir(co) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] >>> co.co_names ('A', 'f', 'a') >>>
訪問PyCodeObject域的py文件:access_demo.py
1 source = open('./demo.py').read() 2 co = compile(source, './demo.py', 'exec') 3 4 #co = co.co_consts[0] #code object A 5 #co = co.co_consts[2] #code object f 6 7 print('type(co) :', type(co)) 8 print('co.co_argcount :', co.co_argcount) 9 print('co.co_kwonlyargcount :', co.co_kwonlyargcount) 10 print('co.co_nlocals :', co.co_nlocals) 11 print('co.co_stacksize :', co.co_stacksize) 12 print('co.co_flags :', co.co_flags) 13 print('co.co_code :', co.co_code) 14 print('co.co_consts :', co.co_consts) 15 print('co.co_names :', co.co_names) 16 print('co.co_varnames :', co.co_varnames) 17 print('co.co_freevars :', co.co_freevars) 18 print('co.co_cellvars :', co.co_cellvars) 19 print('co.co_filename :', co.co_filename) 20 print('co.co_name :', co.co_name) 21 print('co.co_firstlineno :', co.co_firstlineno) 22 print('co.co_lnotab :', co.co_lnotab)
運行結果爲demo.py文件全局的PyCodeObject的信息:
1 [root@lq dis]# python access_demo.py 2 type(co) : <class 'code'> 3 co.co_argcount : 0 4 co.co_kwonlyargcount : 0 5 co.co_nlocals : 0 6 co.co_stacksize : 3 7 co.co_flags : 64 8 co.co_code : b'Gd\x00\x00d\x01\x00\x84\x00\x00d\x01\x00\x83\x02\x00Z\x00\x00d\x02\x00d\x03\x00\x84\x00\x00Z\x01\x00e\x00\x00\x83\x00\x00Z\x02\x00e\x01\x00\x83\x00\x00\x01d\x04\x00S' 9 co.co_consts : (<code object A at 0x7f471304cb70, file "./demo.py", line 1>, 'A', <code object f at 0x7f4712b66db0, file "./demo.py", line 3>, 'f', None) 10 co.co_names : ('A', 'f', 'a') 11 co.co_varnames : () 12 co.co_freevars : () 13 co.co_cellvars : () 14 co.co_filename : ./demo.py 15 co.co_name : <module> 16 co.co_firstlineno : 1 17 co.co_lnotab : b'\x13\x02\x0c\x02\t\x01'
去掉access_demo.py第4行的註釋:獲得類A對應的PyCodeObject
1 [root@lq dis]# python access_demo.py 2 type(co) : <class 'code'> 3 co.co_argcount : 1 4 co.co_kwonlyargcount : 0 5 co.co_nlocals : 1 6 co.co_stacksize : 1 7 co.co_flags : 66 8 co.co_code : b'|\x00\x00Ee\x00\x00Z\x01\x00d\x00\x00Z\x02\x00d\x01\x00S' 9 co.co_consts : ('A', None) 10 co.co_names : ('__name__', '__module__', '__qualname__') 11 co.co_varnames : ('__locals__',) 12 co.co_freevars : () 13 co.co_cellvars : () 14 co.co_filename : ./demo.py 15 co.co_name : A 16 co.co_firstlineno : 1 17 co.co_lnotab : b'\x10\x01'
去掉access_demo.py第5行的註釋:獲得函數f對應的PyCodeObject
1 [root@lq dis]# python access_demo.py 2 type(co) : <class 'code'> 3 co.co_argcount : 0 4 co.co_kwonlyargcount : 0 5 co.co_nlocals : 0 6 co.co_stacksize : 1 7 co.co_flags : 67 8 co.co_code : b'd\x00\x00S' 9 co.co_consts : (None,) 10 co.co_names : () 11 co.co_varnames : () 12 co.co_freevars : () 13 co.co_cellvars : () 14 co.co_filename : ./demo.py 15 co.co_name : f 16 co.co_firstlineno : 3 17 co.co_lnotab : b'\x00\x01'
4.pyc文件的生成
根據前面所述,執行普通的.py程序如python demo.py是不會產生pyc的文件,可能由於編譯器認爲demo.py可能僅運行一次,不會被重用的,因此沒有將編譯生成PyCodeObject對象存儲爲pyc文件。
那麼如何生成pyc文件呢?
(1)使用import demo
在Python運行的過程當中,若是碰到import demo這樣的語句,那麼Python將在設定好的path中尋找demo.pyc或者demo.dll文件,若是沒有找到這些文件,而只是發現了demo.py,而後Python會首先將demo.py編譯成相應的PyCodeObject的中間結果,接着建立demo.pyc文件,並將中間結果寫入該文件。接下來,Python纔會對demo.pyc文件進行import的動做,實際上就是根據demo.pyc文件中記錄的編譯結果直接創建內存中的PyCodeObject。
1 [root@lq dis]# ls 2 access_demo.py demo1.py demo2.py demo3.py demo.py test.py 3 [root@lq dis]# python 4 Python 3.3.0 (default, Nov 21 2012, 11:37:07) 5 [GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux 6 Type "help", "copyright", "credits" or "license" for more information. 7 >>> import demo 8 >>> exit() 9 [root@lq dis]# ls 10 access_demo.py demo1.py demo2.py demo3.py demo.py __pycache__ test.py 11 [root@lq dis]# cd __pycache__/ 12 [root@lq __pycache__]# ls 13 demo.cpython-33.pyc
從上面的例子,能夠看出import demo以後,在demo.py所在目錄生成了一個__pycache__文件夾,該文件夾下有一個demo.cpython-33.pyc的文件,該pyc文件就是咱們想要的。
pyc文件是一個二進制文件。在Windows下能夠經過UE查看:
Linux能夠經過Vim查看:vim -b demo.cpython-33.pyc,而後輸入命令::%!xxd查看,使用:%!xxd -r返回。
pyc文件的文件格式(清楚PyCodeObject中域的含義是瞭解pyc文件格式的基礎)及其具體建立過程,在後續部分會詳細介紹。
(2)使用py_compile.compile()
py_compile模塊詳見:http://docs.python.org/3/library/py_compile.html
The py_compile module provides a function to generate a byte-code file from a source file, and another function used when the module source file is invoked as a script.
py_compile.compile(file, cfile=None, dfile=None, doraise=False, optimize=-1)
Compile a source file to byte-code and write out the byte-code cache file.
The source code is loaded from the file name file.
The byte-code is written to cfile, which defaults to the PEP 3147 path, ending in .pyc (.pyo if optimization is enabled in the current interpreter). For example, if file is/foo/bar/baz.py cfile will default to /foo/bar/__pycache__/baz.cpython-32.pyc for Python 3.2.
If dfile is specified, it is used as the name of the source file in error messages when instead of file.
If doraise is true, a PyCompileError is raised when an error is encountered while compiling file. Ifdoraise is false (the default), an error string is written to sys.stderr, but no exception is raised.
This function returns the path to byte-compiled file, i.e. whatever cfile value was used.
optimize controls the optimization level and is passed to the built-in compile() function. The default of -1 selects the optimization level of the current interpreter.
1 [root@lq dis]# ls 2 access_demo.py demo1.py demo2.py demo3.py demo.py __pycache__ test.py 3 [root@lq dis]# rm -rf __pycache__/ 4 [root@lq dis]# ls 5 access_demo.py demo1.py demo2.py demo3.py demo.py test.py 6 [root@lq dis]# python 7 Python 3.3.0 (default, Nov 21 2012, 11:37:07) 8 [GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux 9 Type "help", "copyright", "credits" or "license" for more information. 10 >>> import py_compile 11 >>> py_compile.compile('./demo.py') 12 './__pycache__/demo.cpython-33.pyc' 13 >>> exit() 14 [root@lq dis]# ls 15 access_demo.py demo1.py demo2.py demo3.py demo.py __pycache__ test.py 16 [root@lq dis]# cd __pycache__/ 17 [root@lq __pycache__]# ls 18 demo.cpython-33.pyc