Python的执行原理

来源:互联网 发布:php 5.3.2.tar.gz 编辑:程序博客网 时间:2024/05/22 11:51

 1. 过程概述

  Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后虚拟机一条一条执行字节码指令,从而完成程序的执行。

  2. 字节码

  字节码在Python虚拟机程序里对应的是PyCodeObject对象。

  .pyc文件是字节码在磁盘上的表现形式。

  3. pyc文件

  PyCodeObject对象的创建时机是模块加载的时候,即import。

  Python test.py会对test.py进行编译成字节码并解释执行,但是不会生成test.pyc。

  如果test.py加载了其他模块,如import util,Python会对util.py进行编译成字节码,生成util.pyc,然后对字节码解释执行。

  如果想生成test.pyc,我们可以使用Python内置模块py_compile来编译。

  加载模块时,如果同时存在.py和.pyc,Python会尝试使用.pyc,如果.pyc的编译时间早于.py的修改时间,则重新编译.py并更新.pyc。

  4. PyCodeObject

  Python代码的编译结果就是PyCodeObject对象。

  typedef struct {

  PyObject_HEAD

  int co_argcount; /* 位置参数个数 */

  int co_nlocals; /* 局部变量个数 */

  int co_stacksize; /* 栈大小 */

  int co_flags;

  PyObject *co_code; /* 字节码指令序列 */

  PyObject *co_consts; /* 所有常量集合 */

  PyObject *co_names; /* 所有符号名称集合 */

  PyObject *co_varnames; /* 局部变量名称集合 */

  PyObject *co_freevars; /* 闭包用的的变量名集合 */

  PyObject *co_cellvars; /* 内部嵌套函数引用的变量名集合 */

  /* The rest doesn’t count for hash/cmp */

  PyObject *co_filename; /* 代码所在文件名 */

  PyObject *co_name; /* 模块名|函数名|类名 */

  int co_firstlineno; /* 代码块在文件中的起始行号 */

  PyObject *co_lnotab; /* 字节码指令和行号的对应关系 */

  void *co_zombieframe; /* for optimization only (see frameobject.c) */

  } PyCodeObject;

  5. pyc文件格式

  加载模块时,模块对应的PyCodeObject对象被写入.pyc文件,格式如下:

Python程序的执行原理    三联教程

  6. 分析字节码

  6.1 解析PyCodeObject

  Python提供了内置函数compile可以编译Python代码和查看PyCodeObject对象,如下:

  Python代码[test.py]

  s = ”hello”

  def func():

  print s

  func()

  在Python交互式shell里编译代码得到PyCodeObject对象:

  dir(co)已经列出co的各个域,想查看某个域直接在终端输出即可:

  test.py的PyCodeObject

  co.co_argcount 0

  co.co_nlocals 0

  co.co_names (‘s’, ’func’)

  co.co_varnames (‘s’, ’func’)

  co.co_consts (‘hello’, , None)

  co.co_code ’dx00x00Zx00x00dx01x00x84x00x00Zx01x00ex01x00x83x00x00x01dx02x00S’

  Python解释器会为函数也生成的字节码PyCodeObject对象,见上面的co_consts[1]

  func的PyCodeObject

  func.co_argcount 0

  func.co_nlocals 0

  func.co_names (‘s’,)

  func.co_varnames ()

  func.co_consts (None,)

  func.co_code ‘tx00x00GHdx00x00S’

  co_code是指令序列,是一串二进制流,它的格式和解析方法见6.2。

  6.2 解析指令序列

  指令序列co_code的格式

  test.py的指令序列

  func函数的指令序列

  第一列表示以下几个指令在py文件中的行号;

  第二列是该指令在指令序列co_code里的偏移量;

  第三列是指令opcode的名称,分为有操作数和无操作数两种,opcode在指令序列中是一个字节的整数;

  第四列是操作数oparg,在指令序列中占两个字节,基本都是co_consts或者co_names的下标;

  第五列带括号的是操作数说明。

  7. 执行字节码

  Python虚拟机的原理就是模拟可执行程序再X86机器上的运行,X86的运行时栈帧如下图:

  假如test.py用C语言来实现,会是下面这个样子:

  const char *s = “hello”;

  void func() {

  printf(“%sn”, s);

  }

  int main() {

  func();

  return 0;

  }

  Python虚拟机的原理就是模拟上述行为。当发生函数调用时,创建新的栈帧,对应Python的实现就是PyFrameObject对象。

  7.1 PyFrameObject

  typedef struct _frame {

  PyObject_VAR_HEAD

  struct _frame *f_back; /* 调用者的帧 */

  PyCodeObject *f_code; /* 帧对应的字节码对象 */

  PyObject *f_builtins; /* 内置名字空间 */

  PyObject *f_globals; /* 全局名字空间 */

  PyObject *f_locals; /* 本地名字空间 */

  PyObject **f_valuestack; /* 运行时栈底 */

  PyObject **f_stacktop; /* 运行时栈顶 */

  …….

  }

  那么对应Python的运行时栈就是这样子:

  7.2 执行指令

  执行test.py的字节码时,会先创建一个栈帧,以下用f表示当前栈帧,执行过程注释如下:

  test.py的符号名集合和常量集合

  co.co_names (‘s’, ’func’)

  co.co_consts (‘hello’, , None)

  test.py的指令序列

  上面的CALL_FUNCTION指令执行时,会创建新的栈帧,并执行func的字节码指令,以下用f表示当前栈帧,func的字节码执行过程如下:

  func函数的符号名集合和常量集合

  func.co_names (‘s’,)

  func.co_consts (None,)

  func函数的指令序列

  7.3 查看栈帧

  如果你想查看当前栈帧,Python提供了sys._getframe()方法可以获取当前栈帧,你只需要在代码里加入代码如下:

  def func():

  import sys

  frame = sys._getframe()

  print frame.f_locals

  print frame.f_globals

  print frame.f_back.f_locals

  #你可以打印frame的各个域

  print s

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑重置开机黑屏了怎么办才好? 龟头有一小块和鱼鳞一样脱皮怎么办 海盗来了赠送碎片密码忘了怎么办 王者荣耀还差几百金币买英雄怎么办 英雄联盟更新后画面突然很卡怎么办 苹果手机微信登陆没反应怎么办 谷歌商店注册短信一直验证怎么办 英雄联盟开游戏退出来进不去怎么办 忘记了路由器和网关的密码怎么办 逆战无尽塔防71关没怪了怎么办 看香的师傅要钱特别多怎么办 电商企业有收入支出没发票怎么办 洗衣液没稀释把衣服染褪色了怎么办 衣服被洗衣液洗褪色了怎么办 b站不小心点了差评怎么办 c盘文件目录损坏且无法读取怎么办 打印发票时发票上的字体变大怎么办 淘宝店铺食品违法遇到打假人怎么办 搜狗输入法说我没有权限安装怎么办 申请移民美国期间护照到期了怎么办 自己申请的qq号账号忘了怎么办 苹果手机下完游戏找不到在哪怎么办 苹果四下游戏的密码忘了怎么办 qq斗地主老自动发消息怎么办 微信小程序斗地主被限制了怎么办 台式电脑玩斗地主总黑屏怎么办 玩斗地主屏幕出现一半玩不了怎么办 电脑qq文件破损或部分丢失怎么办 华为平板电脑开机密码忘记了怎么办 微信被太多人投诉被限制登录怎么办 微信账号被永久封号里面的钱怎么办 乱世王者领礼包时账号异常怎么办 qq填写资料见证号格式错误怎么办 如果把微信注销 王者的号怎么办 93元的吃鸡号忘了激活吗怎么办 王者荣耀实名注册不是自己的怎么办 苹果手机打开qq太慢了怎么办 剪辑视频打开了软件关闭不了怎么办 玩永恒纪元手游网络老掉线怎么办 绝地求生买的钥匙激活码忘了怎么办 魅族手机移动网络打不开网页怎么办