这里有个博客讲 Python 内部机制,已经有一些中文翻译

可能因为我用的Python 3.5,例子跑起来有些不一样。

此外,我又查了其他一些参考资料,总结如下:

Python 的执行方式

先看一个比较详细的步骤分解:

>>> a = "hello"

输入这行代码之后,你一按回车,Python就会执行四步操作:

1  lexing: 词法分析,就是把一个句子分解成 token。大致来说,就是用str.split()可以实现的功能。

2  parsing:解析,就是把这些 token 组装成一个逻辑结构。

3  compiling:编译,把这个逻辑结构转化成一个或者多个code object (代码对象)

4  interpreting:解释,执行每个code object 代表的代码。

还有一种比较简单的说法是这样的:

Python 程序的执行过程就是,它先把代码编译成 bytecode (字节码)指令,交给虚拟机,逐条执行 bytecode 指令。

这两种说法基本上是一样的,只是存在一个code object 和 bytecode 的差异。那么它们之间存在怎样的关系呢?

从操作上说,bytecode 可以在 code object 的属性中找到。

分清function object、code object ,以及 bytecode

>>> def double(a):
return a*2 >>> double
<function double at 0x000001D8082E48C8>

为什么粘贴到这里对齐会是这样?先不管了。

从上面可以看到,定义一个函数之后,它就成了一个function object (函数对象)。只要不使用函数调用符号——也就是小括号——这个函数就不会执行。

但是它已经被编译了,可以通过这个function object 的__code__ 属性找到它的 code object

>>> def double(a):
return a*2

>>> double
<function double at 0x00000169C5F7FF28>

>>> type (double)
<class 'function'>

>>> double.__code__  #找到double 函数对象的 code object

<code object double at 0x00000169C5F36AE0, file "<pyshell#58>", line 1>

>>> type(double.__code__)
<class 'code'>

最后一行可以看到, code object 的类型是 ‘code’

前面说过,bytecode 是 code object 的一个属性的值。这个属性名为 co_code

在 code object 的co_code属性里面,存放了一个字符串,它就是bytecode 序列:

>>> double.__code__.co_code
b'|\x00\x00d\x01\x00\x14S'

bytecode 是几个意思?

>>> double.__code__.co_code
b'|\x00\x00d\x01\x00\x14S'
>>> type(double.__code__.co_code)
<class 'bytes'>
>>> len(double.__code__.co_code)
8

它的类型是‘bytes’ ,长度是8。 你可能觉得奇怪,这个8是怎么数出来的?

注意: Python 3 中 str 类型大致相当于 Python 2 中的unicode 类型,但是 Python 3 中 bytes 类型并不是Python 2 中的 str 类型改了个名字。

bytes 是二进制序列,它的每个元素都是一个整数,值在0-255之间。

>>> for i in double.__code__.co_code:
print (i, end=" ") 124 0 0 100 1 0 20 83

>>> double.__code__.co_code[-1]
83

是不是正好8个元素? 第一个是124,最后一个是83

>>> chr(124)
'|'
>>> chr(83)
'S'

这里是一个很让人迷惑的地方:为什么要把 '|' 、'S'这样的字符和 x00 这样的十六进制表示混在一起?这其实只是Python 在显示 bytes 类型的对象给你看的时候,会把ASCII 码范围内的十六进制元素直接用ASCII 字符显示出来。就像你们学校的成绩光荣榜上,前20名会显示照片,第21名之后只显示名字了。人家的显示方法就是这样。

这段 bytecode 由8个整数组成,每个整数都有深刻的含义,不亚于昆汀的《八恶人》

可能你已经猜到,其中必定有一些代表着指令,整数是一个字典中的键,我们需要的是这个字典中的值,也就是指令的名字

这个字典就在文件opcode.py里。

def_op('LOAD_CONST', 100)       # Index in const list
def_op('BUILD_TUPLE', 102) # Number of tuple items
def_op('BUILD_LIST', 103) # Number of list items
def_op('BUILD_SET', 104) # Number of set items

好像……这些整数才是键值对里的值,我们需要的是键。

有一个方法帮你找出值 (不要忘了先 import opcode)

>>> opcode.opmap["LOAD_FAST"]
124
>>> opcode.opmap["RETURN_VALUE"]
83

找值好像没什么意思嘛,我们更需要的是找到键。

>>> opcode.opname[83]
'RETURN_VALUE'
>>> opcode.opname[124]
'LOAD_FAST'

其实找键也不需要,Python 有个dis反汇编工具可以用 (不要忘了先 import dis)
>>> dis.dis(double)
2 0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 (2)
6 BINARY_MULTIPLY
7 RETURN_VALUE
再回头看看那8个整数(这就是 bytecode的意思 —— 用for循环把 bytecode 迭代一遍得到的数字,代表一个指令序列 )

      124    0    0    100    1    0    20    83  
偏移量  0     1    2     3     4    5    6     7 

很明显,第2列 的0 3 6 7 ,就是每个字节的偏移量咯

下篇在这里

理解 Python 的执行方式,与字节码 bytecode 玩耍 (上)的更多相关文章

  1. 理解 Python 的执行方式,与字节码 bytecode 玩耍 (下)

    上次写到,Python 的执行方式是把代码编译成bytecode(字节码)指令,然后由虚拟机来执行这些 bytecode 而 bytecode 长成这个样子:  b'|\x00\x00d\x01\x0 ...

  2. 任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行

    任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行 多线程 - 廖雪峰的官方网站 https://www.liaoxuefeng ...

  3. 从底层理解Python的执行

    摘要:是否想在Python解释器的内部晃悠一圈?是不是想实现一个Python代码执行的追踪器?没有基础?不要怕,这篇文章让你初窥Python底层的奥妙. [编者按]下面博文将带你创建一个字节码级别的追 ...

  4. Python 字节码bytecode

    字节码bytecode python把源码文件编译成字节码文件,存放在__pycahe子目录内,用.pyc结尾.之后如果不再修改源码文件,运行时则使用*.pyc文件编译成机器码,这样不但运行速度快,而 ...

  5. 深入理解java虚拟机(5)---字节码执行引擎

    字节码是什么东西? 以下是百度的解释: 字节码(Byte-code)是一种包含执行程序.由一序列 op 代码/数据对组成的二进制文件.字节码是一种中间码,它比机器码更抽象. 它经常被看作是包含一个执行 ...

  6. 深入理解JVM虚拟机5:虚拟机字节码执行引擎

    虚拟机字节码执行引擎   转自https://juejin.im/post/5abc97ff518825556a727e66 所谓的「虚拟机字节码执行引擎」其实就是 JVM 根据 Class 文件中给 ...

  7. 深入理解Java虚拟机06--虚拟机字节码执行引擎

    一.前言 物理机的执行引擎是直接在物理硬件如CPU.操作系统.指令集上运行的,但是对于虚拟机来讲,他的执行引擎由自己实现. 执行引擎有统一的外观(Java虚拟机规范),不同类型的虚拟机都遵循了这一规范 ...

  8. JVM学习第三天(JVM的执行子系统)之字节码指令

    早上看了Class类文件结构,晚上继续来看字节码指令,毕竟谁也不是一步登天的(说白了还是穷); 字节码指令 Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode ...

  9. 【JVM源码解析】模板解释器解释执行Java字节码指令(上)

    本文由HeapDump性能社区首席讲师鸠摩(马智)授权整理发布 第17章-x86-64寄存器 不同的CPU都能够解释的机器语言的体系称为指令集架构(ISA,Instruction Set Archit ...

随机推荐

  1. java项目测试或者不使用request,如何获取webroot路径

    1.使用jdk中的方法,然后根据项目编译后的文件存在的位置,获取到classes目录,然后向上级查询获取String path = EngineTest.class.getResource(" ...

  2. oracle可重复执行脚本(添加字段)

    --添加债券期限字段 declare cn integer; begin cn := 0; select count(*) into cn from user_tab_cols t where t.t ...

  3. VMware虚拟机配置端口转发(端口映射),实现远程访问【转】

    前言本文所写的远程为各个电脑在同一个网段内 本文主要详细介绍如何远程访问虚拟机里面的项目! 机器:虚拟机(装在电脑1里).电脑1(宿主机).电脑2.电脑3.电脑4.电脑n... 操作步骤: step1 ...

  4. @RequestBody配合@JsonFormat注解实现字符串自动转换成Date

    2018年08月28日 16:41:15 混合动力火锅 阅读数:440   在controller中使用@RequestBody可以自动将字符串转换成int或者将int转换成字符串,但是Date类型则 ...

  5. 149. Max Points on a Line同一条线上的最多点数

    [抄题]: Given n points on a 2D plane, find the maximum number of points that lie on the same straight ...

  6. faiss学习

    faiss 学习 github wiki 介绍 Faiss:Facebook开源的相似性搜索类库 安装 在Mac系统编译安装Faiss faiss教程跟进--Makefile 编译 faiss安装 m ...

  7. Windows下PythonQt3.2使用pandas.pivot_table

     本机环境 1.win7 64 旗舰版 2.Qt 5.9.1(MSVC 2015,32 bit) 3.Python 3.7.1 (32-bit),二进制包安装的,即Windows x86 execut ...

  8. Idea创建简单Java Web项目并部署Servlet

    1.打开Idea,创建JAVA Web项目 在WEB-INF目录下创建classes和lib文件夹 配置编译输出路径为刚才新建的classes文件夹 配置依赖jar包加载路径 添加tomcat ser ...

  9. HTML第二篇

    1>压缩文件格式:使用.zip格式较好 2>charset(字符集)  国内最新字符集格式为:gb18030   国际上通用的字符集是:UTF-8 3>添加图片 <img sr ...

  10. js使用锚点回到顶部

    使用锚点链接是一种简单的返回顶部的功能实现.该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置 <body s ...