zoukankan      html  css  js  c++  java
  • python 字节码死磕

    前言:

       如果你跟我一样,对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介绍

  • 相关阅读:
    jq元素拖拽
    路径中取文件名
    HBase相关问题
    HBase数据模型
    HBase安装过程
    HBase物理模型
    Hadoop性能调优
    Hive性能调优
    Hadoop资源调度器
    Hive的执行生命周期
  • 原文地址:https://www.cnblogs.com/yinguohai/p/11158492.html
Copyright © 2011-2022 走看看