复杂内建对象的创建

在上一章Python虚拟机中的一般表达式(一)中,我们看到了Python是如何创建一个空的字典对象和列表对象,那么如果创建一个非空的字典对象和列表对象,Python的行为又是如何呢?demo2.py里面包含一个字典对象和列表对象,这两个对象都是在初始化时就包含元素,首先,我们看一下对应PyCodeObject中的符号表和常量表

  1. # cat demo2.py
  2. i = 1
  3. s = "Python"
  4. d = {"1": 1, "2": 2}
  5. l = [1, 2]
  6. # python2.5
  7. ……
  8. >>> source = open("demo2.py").read()
  9. >>> co = compile(source, "demo2.py", "exec")
  10. >>> co.co_names
  11. ('i', 's', 'd', 'l')
  12. >>> co.co_consts
  13. (1, 'Python', '1', 2, '2', None)

      

其次,我们再用dis模块解释一下demo2.py所对应的字节码

  1. >>> import dis
  2. >>> dis.dis(co)
  3. 1 0 LOAD_CONST 0 (1)
  4. 3 STORE_NAME 0 (i)
  5.  
  6. 2 6 LOAD_CONST 1 ('Python')
  7. 9 STORE_NAME 1 (s)
  8.  
  9. 3 12 BUILD_MAP 0
  10. 15 DUP_TOP
  11. 16 LOAD_CONST 0 (1)
  12. 19 ROT_TWO
  13. 20 LOAD_CONST 2 ('1')
  14. 23 STORE_SUBSCR
  15. 24 DUP_TOP
  16. 25 LOAD_CONST 3 (2)
  17. 28 ROT_TWO
  18. 29 LOAD_CONST 4 ('2')
  19. 32 STORE_SUBSCR
  20. 33 STORE_NAME 2 (d)
  21.  
  22. 4 36 LOAD_CONST 0 (1)
  23. 39 LOAD_CONST 3 (2)
  24. 42 BUILD_LIST 2
  25. 45 STORE_NAME 3 (l)
  26. 48 LOAD_CONST 5 (None)
  27. 51 RETURN_VALUE

    

现在,我们来分析一下Python虚拟机是如何创建包含元素的字典对象和列表对象

首先是字典对象:

  1. d = {"1": 1, "2": 2}
  2. //分析结果
  3. 1 12 BUILD_MAP 0
  4. 15 DUP_TOP
  5. 16 LOAD_CONST 0 (1)
  6. 19 ROT_TWO
  7. 20 LOAD_CONST 2 ('1')
  8. 23 STORE_SUBSCR
  9. 24 DUP_TOP
  10. 25 LOAD_CONST 3 (2)
  11. 28 ROT_TWO
  12. 29 LOAD_CONST 4 ('2')
  13. 32 STORE_SUBSCR
  14. 33 STORE_NAME 2 (d)

    

BUILD_MAP会创建一个空的字典,并压入运行时栈,这没什么可说的,我们看下BUILD_MAP之后的指令DUP_TOP

ceval.c

  1. case DUP_TOP:
  2. v = TOP();
  3. Py_INCREF(v);
  4. PUSH(v);
  5. goto fast_next_opcode;

  

DUP_TOP会获取栈顶的元素,增加其引用,又再一次将栈顶元素压入栈中,紧接着LOAD_CONST指令又会将1这个对象压入到运行时栈,那么我们来看下前3条指令执行完毕后运行时栈和名字空间的分布:

图1-1

Python虚拟机在接下来又执行指令ROT_TWO,我们再来看一下关于这条指令所做的内容:

ceval.c

  1. case ROT_TWO:
  2. v = TOP();
  3. w = SECOND();
  4. SET_TOP(w);
  5. SET_SECOND(v);
  6. goto fast_next_opcode;

  

ROT_TWO也是调用其他宏来完成任务的,我们看一下这几条宏的指令:

ceval.c

  1. #define TOP() (stack_pointer[-1])
  2. #define SECOND() (stack_pointer[-2])
  3. #define SET_TOP(v) (stack_pointer[-1] = (v))
  4. #define SET_SECOND(v) (stack_pointer[-2] = (v))

  

原来ROT_TWO这条指令会取出运行时栈的第一个元素和第二个元素,然后将其位置对调,执行完ROT_TWO之后,我们再来看一下运行时栈和名字空间的分布:

图1-2

随后又执行了一条LOAD_CONST指令,将字符串'1'压入到运行时栈中,之后,又执行了STORE_SUBSCR这条指令,而正是这条指令将字符串"1"和整数值1之间的映射建立在之前的字典对象上,我们来看一下STORE_SUBSCR的内容:

  1. case STORE_SUBSCR:
  2. w = TOP();
  3. v = SECOND();
  4. u = THIRD();
  5. STACKADJ(-3);
  6. /* v[w] = u */
  7. err = PyObject_SetItem(v, w, u);
  8. Py_DECREF(u);
  9. Py_DECREF(v);
  10. Py_DECREF(w);
  11. if (err == 0) continue;
  12. break;

  

w是之前压入栈中的字符串"1",而v是运行时栈的自栈顶开始的第二个元素,是字典对象,而u则是最早之前压入栈中的值,即为整数值1,通过PyObject_SetItem(v, w, u)建立字符串"1"和整数值1在字典上的映射关系。同理字符串"2"和整数值2也是基于一样的字节码建立的映射关系,最后执行STORE_NAME字节码,在名字空间上建立符号d和字典对象的映射

在成功创建字典对象后并赋予初值,还会创建列表对象,列表对象会先将初值用LOAD_CONST压入运行时栈,再调用BUILD_LIST时将栈中的元素一个个压入列表对象,BUILD_LIST的内容在上一章Python虚拟机中的一般表达式(一)中已经解释,这里不再重复

  1. l = [1, 2]
  2. //分析结果
  3. 4 36 LOAD_CONST 0 (1)
  4. 39 LOAD_CONST 3 (2)
  5. 42 BUILD_LIST 2
  6. 45 STORE_NAME 3 (l)

  

Python虚拟机中的一般表达式(二)的更多相关文章

  1. Python虚拟机中的一般表达式(三)

    其他一般表达式 在前两章:Python虚拟机中的一般表达式(一).Python虚拟机中的一般表达式(二)中,我们介绍了Python虚拟机是怎样执行创建一个整数值对象.字符串对象.字典对象和列表对象.现 ...

  2. Python虚拟机中的一般表达式(一)

    在Python虚拟机框架这一章中,我们通过PyEval_EvalFrameEx看到了Python虚拟机的整体框架.而这章开始,我们将了解Python虚拟机是如何完成对Python的一般表达式的执行,这 ...

  3. 《python解释器源码剖析》第10章--python虚拟机中的一般表达式

    10.0 序 上一章中,我们通过PyEval_EvalFrameEx看到了python虚拟机的整体框架,那么这一章我们将深入到PyEval_EvalFrameEx的各个细节当中,深入剖析python的 ...

  4. (Python学习9)Python虚拟机中的一般表达式

    1.准备工作 执行.py程序时,Python解释器对PyCodeObject的co_code存储的字节码进行解释执行,同时co_consts存储了常量,co_names存储了变量名称.用compile ...

  5. 《python解释器源码剖析》第11章--python虚拟机中的控制流

    11.0 序 在上一章中,我们剖析了python虚拟机中的一般表达式的实现.在剖析一遍表达式是我们的流程都是从上往下顺序执行的,在执行的过程中没有任何变化.但是显然这是不够的,因为怎么能没有流程控制呢 ...

  6. python虚拟机中的异常流控制

    异常:对程序运行中的非正常情况进行抽象.并且提供相应的语法结构和语义元素,使得程序员能够通过这些语法结构和语义元素来方便地描述异常发生时的行为. 1.Python中的异常机制: 1.1Python虚拟 ...

  7. 《python解释器源码剖析》第13章--python虚拟机中的类机制

    13.0 序 这一章我们就来看看python中类是怎么实现的,我们知道C不是一个面向对象语言,而python却是一个面向对象的语言,那么在python的底层,是如何使用C来支持python实现面向对象 ...

  8. 《python解释器源码剖析》第12章--python虚拟机中的函数机制

    12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python ...

  9. 《python源代码剖析》笔记 python虚拟机中的函数机制

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.Python虚拟机在运行函数调用时会动态地创建新的 PyFrameObject对象, 这 ...

随机推荐

  1. HandlerMapping执行过程。。。

    1.web.xml DispatcherServlet 类 寻址 doDispatch() 2.getHandler(requset) 点击,进入 3.HandlerMapping hm=xxxxxx ...

  2. 选择控件js插件和使用方法

    记录一下 选择控件js插件 /* * 滚动控件,包含地址选择.时间选择.自定义单选 */ //js_inputbox input 输入框 //js_pickviewselect 下拉单项选择 //js ...

  3. 【翻译转载】【官方教程】Asp.Net MVC4入门指南(6):验证编辑方法和编辑视图

    本节中,您将开始修改为电影控制器所新加的操作方法和视图.然后,您将添加一个自定义的搜索页. 在浏览器地址栏里追加/Movies, 浏览到Movies页面.并进入编辑(Edit)页面. Edit(编辑) ...

  4. 关于 SQL Server Reporting Services 匿名登录的解决方案

    每次访问报表都需要windows验证,这样的报表给客户确实很说不过去. SSRS 可以匿名登录的设定步骤: 环境: 开发工具:SQL Server Business Intelligence Deve ...

  5. AJPFX总结Java 类加载器

    顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中.一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java ...

  6. c/c++的const和static区别

    C语言中的const和static用来修饰变量或者函数,用const修饰表示不可改变,用static修饰表示变量或者函数是静态的,作用域控制在函数内. const定义的常量在超出其作用域之后其空间会被 ...

  7. python3操作excel02(对excel的基础操作,进行简单的封装)3

    #!/usr/bin/env python# -*- coding:UTF-8 -*- import requestsfrom bs4 import BeautifulSoupfrom bs4 imp ...

  8. jsp四大作用域之Session

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding= ...

  9. UVA 10382 Watering Grass (区间覆盖,贪心)

    问题可以转化为草坪的边界被完全覆盖.这样一个圆形就换成一条线段. 贪心,从中选尽量少的线段把区间覆盖,按照把线段按左端点排序,记录一个当前已经覆盖区间的位置cur, 从左端点小于等于cur选一个右端点 ...

  10. UVA439 knightMoves (A*启发搜索)

    第一个A*,纪念下. A*要保证最短路一定要估价函数小于等于实际值,越接近越好 估价函数取Manhattan距离除以二. //Rey #include<cstdio> #include&l ...