python 字节码死磕

摘要:
如果您不知道如何生成python字节码文件,那么python代码将被编译成字节码(一种类似于汇编指令的中间语言)。字节码由python虚拟机执行。注意:一条python语句将对应几个字节码指令,每个字节指令对应一个函数偏移量。dis模块可以反汇编CPython代码,源代码行号|指令偏移量|指令符号|指令参数|实际参数值描述:

python 字节码死磕第1张
前言:

   如果你跟我一样,对python的字节码感兴趣,想了解python的代码在内存中到底是怎么去运行的,那么你可以继续往下看,如果你是python新手,我建议你移步它处,本文适合有点基础的python读者。
   如果你不知道怎么生成python的字节码文件,可以查阅我的 python 代码反汇编  的博文  
 
 
python代码的执行过程:
  1. python代码编译成字节码【类似于汇编指令的中间语言】
  2. 字节码由python虚拟机来执行编译后的字节码
 
说明:
         一个python语句会对应若个字节码指令,每个字节指令又对应着一个函数偏移量,可以理解为指令的ID
 
        虚拟机一条一条执行字节码指令,从而完成程序的执行,而dis模块可以对CPython代码进行反汇编,生成字节码指令
 
 
dis.dis() 转化后的字节码格式如下:
源码行号  |  指令偏移量  | 指令符号 | 指令参数  |  实际参数值
       
说明: 不同版本的CPython 指令长度可能不同,但是 3.7的每条指令是2个字节,所以我们去看dis 生成的字节码指令集的时候,指令偏移量总是从0开始,每增加一条在原来的偏移量上增加2
    故,指令偏移量的值,一般都是: 0 , 2 , 4, 6 , 8 , ... , 2n ( n>=0 )
 
变量指令解析

 
变量 — _const
 
LOAD_CONST :加载const 变量,比如数值,字符串等等, 一般用于传递给函数作为参数
 
案例一:
test(2,'hello')

  

对应的字节码指令
 
1             0 LOAD_NAME                0 (test)    
              2 LOAD_CONST               0 (2)
              4 LOAD_CONST               1 ('hello')
              6 CALL_FUNCTION            2            
              8 POP_TOP
             10 LOAD_CONST               2 (None)
             12 RETURN_VALUE
 
 
局部变量 — _FAST
 
LOAD_FAST :一般用于加载局部变量的值,也就是读取值,用于计算或者函数调用传传等
STORE_FAST :一般用于保存值到局部变量
 
案例二:
 
n = n / p
 
对应的字节码指令
1             0 LOAD_NAME                0 (n)
              2 LOAD_NAME                1 (p)
              4 BINARY_TRUE_DIVIDE
              6 STORE_NAME               0 (n)
              8 LOAD_CONST               0 (None)
             10 RETURN_VALUE
 
说明: 函数的形参也是局部变量,那么如何区分局部变量中的形参呢?
    形参是没有初始化的,所以如果发现发现操作的一个局部变量只有 LOAD_FAST 而没有 STORE_FAST,那么这个变量就是形参了。而其它的局部变量在使用之前肯定会使用STORE_FAST进行初始化。
 
案例三:
def test(arg1):
     num = 0
     print(num, arg1)
 
对应的字节码指令
  1           0 LOAD_CONST               0 (<code object test at 0x10546c150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x10546c150, file "code.py", line 1>:
  2           0 LOAD_CONST               1 (0)
              2 STORE_FAST               1 (num)
 
  3           4 LOAD_GLOBAL              0 (print)
              6 LOAD_FAST                1 (num)
              8 LOAD_FAST                0 (arg1).  #只有LOAD_FAST ,没有 STORE_FAST
             10 CALL_FUNCTION            2
             12 POP_TOP
             14 LOAD_CONST               0 (None)
             16 RETURN_VALUE
全局变量 — _GLOBAL
 
    LOAD_GLOBAL : 用来加载全局变量, 包括制定函数名,类名,模块名等全局符号
    STORE_GLOBAL :用来给全局变量赋值
 
案例四
def test(arg1):
     global age
     age = 20
     print(age)

  

对应的字节码指令
  1           0 LOAD_CONST               0 (<code object test at 0x1056e3150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('test')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (test)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
Disassembly of <code object test at 0x1056e3150, file "code.py", line 1>:
  3           0 LOAD_CONST               1 (20)
              2 STORE_GLOBAL             0 (age)
 
  4           4 LOAD_GLOBAL              1 (print)
              6 LOAD_GLOBAL              0 (age)
              8 CALL_FUNCTION            1
             10 POP_TOP
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE
 
常用数据类型

 
1.list
 
BUILD_LIST :  用于创建一个 list 结构
 
案例五
a = [1, 2]
 
对应的字节码指令
  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 BUILD_LIST               2
              6 STORE_NAME               0 (a)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE                      //程序结束
 
案例六
[ x for x in range(4) if x > 2 ]
 
对应的字节码
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x10bffa150, file "code.py", line 1>)
              2 LOAD_CONST               1 ('<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (range)
              8 LOAD_CONST               2 (4)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 LOAD_CONST               3 (None)
             20 RETURN_VALUE
 
Disassembly of <code object <listcomp> at 0x10bffa150, file "code.py", line 1>:
  1           0 BUILD_LIST               0               //创建 list , 为赋值给某变量,这种时候一般都是语法糖结构了
              2 LOAD_FAST                0 (.0)        
        >>    4 FOR_ITER                16 (to 22)      //开启迭代循环
              6 STORE_FAST               1 (x)          //局部变量x
              8 LOAD_FAST                1 (x)          // 导入 x
             10 LOAD_CONST               0 (2)          // 导入 2
             12 COMPARE_OP               4 (>)          // x 与 2 进行比较,比较符号为 >
             14 POP_JUMP_IF_FALSE        4              // 不满足条件就跳过 “出栈“ 动作,既,continue" >>  4 FOR_ITER. “ 处
             16 LOAD_FAST                1 (x)          // 读取满足条件的局部变量x
             18 LIST_APPEND              2              // 把满足条件的x 添加到list中
             20 JUMP_ABSOLUTE            4              
        >>   22 RETURN_VALUE                            //程序结束
 
 
2.dict
 
BUILD_MAP : 用于创建一个空的dict 
STORE_MAP : 用于初始化 dict 中的内容,赋值给变量
 
案例七
k = {'a': 1}
 
对应的字节码
  1           0 LOAD_CONST               0 ('a')
              2 LOAD_CONST               1 (1)
              4 BUILD_MAP                1
              6 STORE_NAME               0 (k)
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE
 
 
3.slice
 
BUILD_SLICE :        用于创建切片, 对于 list , tuple , 字符串都可以使用slice 的方式进行访问
BINARY_SUBSCR : 读取slice 的值
STORE_SUBSCR :   slice 的值赋值给变量。
 
案例八
num = [1, 2, 3]
a = num[1:2]
b = num[0:1:1]
num[1:2] = [10, 11]

  

对应的字节码
  1           0 LOAD_CONST               0 (1)
              2 LOAD_CONST               1 (2)
              4 LOAD_CONST               2 (3)
              6 BUILD_LIST               3
              8 STORE_NAME               0 (num)
 
  2          10 LOAD_NAME                0 (num)
             12 LOAD_CONST               0 (1)
             14 LOAD_CONST               1 (2)
             16 BUILD_SLICE              2       #创建了一个切片
             18 BINARY_SUBSCR                 #读取切片中的值
             20 STORE_NAME               1 (a)   #将读取切片中的值赋值给变量 a
 
  3          22 LOAD_NAME                0 (num)
             24 LOAD_CONST               3 (0)
             26 LOAD_CONST               0 (1)
             28 LOAD_CONST               0 (1)
             30 BUILD_SLICE              3
             32 BINARY_SUBSCR
             34 STORE_NAME               2 (b)
 
  4          36 LOAD_CONST               4 (10)
             38 LOAD_CONST               5 (11)
             40 BUILD_LIST               2
             42 LOAD_NAME                0 (num)
             44 LOAD_CONST               0 (1)
             46 LOAD_CONST               1 (2)
             48 BUILD_SLICE              2
             50 STORE_SUBSCR
             52 LOAD_CONST               6 (None)
             54 RETURN_VALUE
 
 
4.循环
 
SETUP_LOOP :用于开始一个循环。 
JUMP_ABSOLUTE: 结束循环
 
案例九
i = 0
while i < 10:
    i += 1

  

对应的字节码
  1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (i)
 
  2           4 SETUP_LOOP              20 (to 26)   // 循环开始处,26表示循环结束点
        >>    6 LOAD_NAME                0 (i)       // “>>" 表示循环切入点
              8 LOAD_CONST               1 (10)
             10 COMPARE_OP               0 (<)
             12 POP_JUMP_IF_FALSE       24
 
  3          14 LOAD_NAME                0 (i)
             16 LOAD_CONST               2 (1)
             18 INPLACE_ADD
             20 STORE_NAME               0 (i)
             22 JUMP_ABSOLUTE            6          // 逻辑上,循环在此处结束
        >>   24 POP_BLOCK                          
        >>   26 LOAD_CONST               3 (None)
             28 RETURN_VALUE 
 
案例十
num = 0
for i in range(5):
    num += i
对应的字节码
  1           0 LOAD_CONST               0 (0)
              2 STORE_NAME               0 (num)
 
  2           4 SETUP_LOOP              24 (to 30)  //开始循环
              6 LOAD_NAME                1 (range)
              8 LOAD_CONST               1 (5)
             10 CALL_FUNCTION            1          //调用range 函数
             12 GET_ITER                            //获取迭代 range 的 iter 
        >>   14 FOR_ITER                12 (to 28)  //开始进行 range 的迭代
             16 STORE_NAME               2 (i)
 
  3          18 LOAD_NAME                0 (num)
             20 LOAD_NAME                2 (i)
             22 INPLACE_ADD
             24 STORE_NAME               0 (num)
             26 JUMP_ABSOLUTE           14
        >>   28 POP_BLOCK
        >>   30 LOAD_CONST               2 (None)
             32 RETURN_VALUE
 
 
5.if
 
POP_JUMP_IF_FALSE : 条件结果为 FALSE  则跳出 目标的偏移指令
JUMP_FORWARD :       直接跳转到目标便宜指令
COMPARE_OP:             比较指令
 
案例十一
num = 20
if num < 10:
    print('lt 10')
elif num > 10:
    print('gt 10')
else:
    print('eq 10')

对应的字节码
  1           0 LOAD_CONST               0 (20)
              2 STORE_NAME               0 (num)
 
  2           4 LOAD_NAME                0 (num)
              6 LOAD_CONST               1 (10)
              8 COMPARE_OP               0 (<)
             10 POP_JUMP_IF_FALSE       22
 
  3          12 LOAD_NAME                1 (print)
             14 LOAD_CONST               2 ('lt 10')
             16 CALL_FUNCTION            1
             18 POP_TOP
             20 JUMP_FORWARD            26 (to 48)
 
  4     >>   22 LOAD_NAME                0 (num)
             24 LOAD_CONST               1 (10)
             26 COMPARE_OP               4 (>)
             28 POP_JUMP_IF_FALSE       40
 
  5          30 LOAD_NAME                1 (print)
             32 LOAD_CONST               3 ('gt 10')
             34 CALL_FUNCTION            1
             36 POP_TOP
             38 JUMP_FORWARD             8 (to 48)
 
  7     >>   40 LOAD_NAME                1 (print)
             42 LOAD_CONST               4 ('eq 10')
             44 CALL_FUNCTION            1
             46 POP_TOP
        >>   48 LOAD_CONST               5 (None)
             50 RETURN_VALUE 

参考资料:

  python 官方 dis介绍

免责声明:文章转载自《python 字节码死磕》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇20191218 实验一 《Python程序设计》实验报告cocos_js写文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

mysql 函数 存储过程 事件(event) job 模板

mysql的编程能力比sqlserver和mysql弱很多,万不得已尽量将这些东西转移到应用层。 but,有时候小项目或项目刚开始尝试阶段,需要降低服务器成本,压缩项目规模。期初业务需求不清晰,也比较简单,为了快速成型也可以先凑合着用。 创建函数模板: -- ---------------------------- -- Function structur...

abap 简单的本地类操作

作业: 1、创建程序,用于本地类测试。 2、创建本地类LCL_AIRPLANE,用于对飞机的名称及型号的管理。 3、创建1个私有实例类型GTY_PLANE,包含2个字段: name(飞机的名称),类型为string, TYPE(飞机的类型),参考SAPLANE-PLANETYPE. 4、创建一个私有实例内表GT_PLANE,一个私有实例GS_PLANE,均...

安装完SAP后BASIS的配置流程

安装完SAP后BASIS配置流程 安装完SAP后,配置流程. 1.升级kernel。 2.TCD SLICENSE: License Administration install > System Num. & license key 3.TCD STMS: Transport Management System 4.DDIC登录,密码为:1...

memcpy多字节字节赋值问题

   以前没注意过多字节赋值问题,考虑的角度是充分利用 cpu 的 32 位带宽。一次复制 1 个字节和一次复制 4 个字节占用的 cpu 指令周期是一样的,既然我们的 cpu 能同时操作 32 位,为什么我们不能一次复制 4 个字节呢?如此一来,总运行的指令数将降低到原来的 1/4 ! 于是有下面代码(henix转自http://www.embedd...

Adobe/Flash Media Server 5.0 linux 64位系统下的安装

一、下载Adobe/Flash MS5.0下载地址:http://fs1.d-h.st/download/00036/VOt/adobemediaserver_5_ls1_linux64.tar.gz# ./wget http://fs1.d-h.st/download/00036/VOt/adobemediaserver_5_ls1_linux64.t...

Docker mysql主从配置

一:Mysql基于Docker的主从复制搭建 1:安装docker,安装步骤可见我之前的文章:Docker-常用基建的安装与部署 docker ps 命令查询当前的容器状态,这就是我们最后要达到的效果。 2:首先拉取mysql官方镜像 bash> docker pull mysql:5.7 演示环境是在同一台服务器上部署。因为docker创建容器时...