閱讀544 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[筆記]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

  上一篇:go QVGA、WVGA、VGA、WQVGA、SQVGA等幾種手機分辨率掃盲!
  下一篇:go [筆記]PyDictObject的哈希算法和搜索過程