[筆記]PyCodeObject初探
在code.h中有PyCodeObject的定義:/* Bytecode object */ typedef struct { PyObject_HEAD int co_argcount; /* #arguments, except *args */ int co_nlocals; /* #local variables */ int co_stacksize; /* #entries needed for evaluation stack */ int co_flags; /* CO_..., see below */ PyObject *co_code; /* instruction opcodes */ PyObject *co_consts; /* list (constants used) */ PyObject *co_names; /* list of strings (names used) */ PyObject *co_varnames; /* tuple of strings (local variable names) */ PyObject *co_freevars; /* tuple of strings (free variable names) */ PyObject *co_cellvars; /* tuple of strings (cell variable names) */ /* The rest doesn't count for hash/cmp */ PyObject *co_filename; /* string (where it was loaded from) */ PyObject *co_name; /* string (name, for reference) */ int co_firstlineno; /* first source line number */ PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See Objects/lnotab_notes.txt for details. */ void *co_zombieframe; /* for optimization only (see frameobject.c) */ PyObject *co_weakreflist; /* to support weakrefs to code objects */ } PyCodeObject;
Python編譯器在將源文件編譯成pyc文件的過程中,會收集字符串、常量值、字節碼等出現在源代碼中的靜態信息。這些信息可以保存在pyc文件中和PyCodeObejct(運行時)。pyc文件實際上就是儲存著PyCodeObject。
如上定義,PyCodeObejct包含許多成員用來保存信息,各個成員的含義都有注釋,分別是類型和含義。
每個名字空間(或者說作用域)都對應一個PyCodeObejct,以下麵的代碼為例:
class A: pass def Foo(arg): i = arg print(i) if __name__ == "__main__": a = A() Foo(1)
首先文件作用域(文件全局)對應一個PyCodeObject,而其中還有類A和函數Foo兩個作用域,也對應著另外兩個PyCodeObject。
將文件作用域對應的PyCodeObject的信息輸入,可以得到如下信息:
<class 'code'> 0 0 3 64 b'Gd\x00\x00\x84\x00\x00d\x01\x00\x83\x02\x00Z\x00\x00d\x02\x00\x84\x00\x00Z\x01\x00e\x02\x00d\x03\x00k\x02\x00r;\x00e\x00\x00\x83\x00\x00Z\x03\x00e\x01\x00d\x04\x00\x83\x01\x00\x01n\x00\x00d\x05\x00S' (<code object A at 0x0247E430, file "./demo.py", line 1>, 'A', <code object Foo at 0x0247E3E0, file "./demo.py", line 4>, '__main__', 1, None) ('A', 'Foo', '__name__', 'a') () () () ./demo.py <module> 1 b'\x10\x03\t\x04\x0c\x01\t\x01'
第一行是額外指定輸入PyCodeObject的類型,接下來是按照PyCodeObject的成員定義順序依次輸出,分別表示:
未知參數個數局部變量個數棧空間標誌位字節碼常量信息符號信息局部變量名集合閉包需要用到的信息嵌套函數所引用的局部變量名集合源文件完整路徑該CodeBlock的名字源文件中對應起始行字節碼與源文件中行號對應關係
可以看到在常量信息中還包含了A、Foo兩個PyCodeObject,下麵再輸出Foo的信息以加深認識:
<class 'code'> 1 2 2 67 b'|\x00\x00}\x01\x00t\x00\x00|\x01\x00\x83\x01\x00\x01d\x00\x00S' (None,) ('print',) ('arg', 'i') () () ./demo.py Foo 4 b'\x00\x01\x06\x01'
以下是用來輸出信息的代碼:
source = open('./demo.py').read() co = compile(source, './demo.py', 'exec') #co = co.co_consts[2] print(type(co)) print(co.co_argcount) print(co.co_nlocals) print(co.co_stacksize) print(co.co_flags) print(co.co_code) print(co.co_consts) print(co.co_names) print(co.co_varnames) print(co.co_freevars) print(co.co_cellvars) print(co.co_filename) print(co.co_name) print(co.co_firstlineno) print(co.co_lnotab)
JasonLee 2011.08.20 13:56
最後更新:2017-04-02 22:16:33