首页 > 代码库 > Python程序执行原理
Python程序执行原理
1.首先在code.h中查看PyCodeObject的struct
1 typedef struct { 2 PyObject_HEAD 3 int co_argcount; /* #arguments, except *args */ 4 int co_nlocals; /* #local variables */ 5 int co_stacksize; /* #entries needed for evaluation stack */ 6 int co_flags; /* CO_..., see below */ 7 PyObject *co_code; /* instruction opcodes */ 8 PyObject *co_consts; /* list (constants used) */ 9 PyObject *co_names; /* list of strings (names used) */10 PyObject *co_varnames; /* tuple of strings (local variable names) */11 PyObject *co_freevars; /* tuple of strings (free variable names) */12 PyObject *co_cellvars; /* tuple of strings (cell variable names) */13 /* The rest doesn‘t count for hash/cmp */14 PyObject *co_filename; /* string (where it was loaded from) */15 PyObject *co_name; /* string (name, for reference) */16 int co_firstlineno; /* first source line number */17 PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See18 Objects/lnotab_notes.txt for details. */19 void *co_zombieframe; /* for optimization only (see frameobject.c) */20 PyObject *co_weakreflist; /* to support weakrefs to code objects */21 } PyCodeObject;
2.加载模块时,模块对应的PyCodeObject对象会被写入 .pyc中,当然在平时的运行代码的过程中,看不到 .pyc文件,
这个过程必须Python 中库函数compile,具体格式如:compile(source, filename, model[, flags[, dont_inherit]])
其中:
source是字符串或AST(abstract sytnax tree)对象.
filename是文件名,如果不是从文件中读出的代码,可传递一些可辨认的值
model是编译参数,有eval,signal,exec。处理的对象不同
后面参数可选
3.测试
(1)PyCodeObject
文件pycodeobject.py
1 #-*-codeing:UTF-8-*-2 s = "hello the cruel world"3 def func():4 print s5 func()
在Python交互式shell里编译代码得到PyCodeObject对象:
>>> src = http://www.mamicode.com/open("./code/pycodeobject.py").read()>>> co = compile(src,"pycodeobject.py",‘exec‘)>>> dir(co)[‘__class__‘, ‘__cmp__‘, ‘__delattr__‘, ‘__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_lnotab‘, ‘co_name‘, ‘co_names‘, ‘co_nlocals‘, ‘co_stacksize‘, ‘co_varnames‘]>>>
pycodeobjec.py的PyCodeObject对象,print即可
>>> print co.co_argcount0>>> print co.co_nlocals0>>> print co.co_names(‘s‘, ‘func‘)>>> print co.co_varnames()>>> print co.co_consts(‘hello the cruel world‘, <code object func at 02118A88, file "pycodeobject.py", line 3>, None)>>> print co.co_coded
解析指令序列
>>> import dis>>> print dis.dis(co) 2 0 LOAD_CONST 0 (‘hello the cruel world‘) 3 STORE_NAME 0 (s) 3 6 LOAD_CONST 1 (<code object func at 02118A88, file "pycodeobject.py", line 3>) 9 MAKE_FUNCTION 0 12 STORE_NAME 1 (func) 5 15 LOAD_NAME 1 (func) 18 CALL_FUNCTION 0 21 POP_TOP 22 LOAD_CONST 2 (None) 25 RETURN_VALUE None>>>
第一列表示以下几个指令在py文件中的行号;
第二列是该指令在指令序列co_code里的偏移量;
第三列是指令opcode的名称,分为有操作数和无操作数两种,opcode在指令序列中是一个字节的整数;
第四列是操作数oparg,在指令序列中占两个字节,基本都是co_consts或者co_names的下标;
第五列带括号的是操作数说明。
(3)PyFrameObject
在frameobject.h查看PyFrameObject对象的数据结构
1 typedef struct _frame { 2 PyObject_VAR_HEAD 3 struct _frame *f_back; /* previous frame, or NULL */ 4 PyCodeObject *f_code; /* code segment */ 5 PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ 6 PyObject *f_globals; /* global symbol table (PyDictObject) */ 7 PyObject *f_locals; /* local symbol table (any mapping) */ 8 PyObject **f_valuestack; /* points after the last local */ 9 /* Next free slot in f_valuestack. Frame creation sets to f_valuestack.10 Frame evaluation usually NULLs it, but a frame that yields sets it11 to the current stack top. */12 PyObject **f_stacktop;13 PyObject *f_trace; /* Trace function */14 15 /* If an exception is raised in this frame, the next three are used to16 * record the exception info (if any) originally in the thread state. See17 * comments before set_exc_info() -- it‘s not obvious.18 * Invariant: if _type is NULL, then so are _value and _traceback.19 * Desired invariant: all three are NULL, or all three are non-NULL. That20 * one isn‘t currently true, but "should be".21 */22 PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;23 24 PyThreadState *f_tstate;25 int f_lasti; /* Last instruction if called */26 /* Call PyFrame_GetLineNumber() instead of reading this field27 directly. As of 2.3 f_lineno is only valid when tracing is28 active (i.e. when f_trace is set). At other times we use29 PyCode_Addr2Line to calculate the line from the current30 bytecode index. */31 int f_lineno; /* Current line number */32 int f_iblock; /* index in f_blockstack */33 PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */34 PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */35 } PyFrameObject;
查看栈帧
1 def func():2 import sys3 frame = sys._getframe()4 print frame.f_locals5 print frame.f_globals6 print frame.f_back.f_locals7 #你可以打印frame的各个域8 print s
此次的代码解析来自Python 2.7版本。
Python程序执行原理
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。