[笔记]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