Python虚拟机中的一般表达式(二)
复杂内建对象的创建
在上一章Python虚拟机中的一般表达式(一)中,我们看到了Python是如何创建一个空的字典对象和列表对象,那么如果创建一个非空的字典对象和列表对象,Python的行为又是如何呢?demo2.py里面包含一个字典对象和列表对象,这两个对象都是在初始化时就包含元素,首先,我们看一下对应PyCodeObject中的符号表和常量表
# cat demo2.py
i = 1
s = "Python"
d = {"1": 1, "2": 2}
l = [1, 2]
# python2.5
……
>>> source = open("demo2.py").read()
>>> co = compile(source, "demo2.py", "exec")
>>> co.co_names
('i', 's', 'd', 'l')
>>> co.co_consts
(1, 'Python', '1', 2, '2', None)
其次,我们再用dis模块解释一下demo2.py所对应的字节码
>>> import dis
>>> dis.dis(co)
1 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (i) 2 6 LOAD_CONST 1 ('Python')
9 STORE_NAME 1 (s) 3 12 BUILD_MAP 0
15 DUP_TOP
16 LOAD_CONST 0 (1)
19 ROT_TWO
20 LOAD_CONST 2 ('1')
23 STORE_SUBSCR
24 DUP_TOP
25 LOAD_CONST 3 (2)
28 ROT_TWO
29 LOAD_CONST 4 ('2')
32 STORE_SUBSCR
33 STORE_NAME 2 (d) 4 36 LOAD_CONST 0 (1)
39 LOAD_CONST 3 (2)
42 BUILD_LIST 2
45 STORE_NAME 3 (l)
48 LOAD_CONST 5 (None)
51 RETURN_VALUE
现在,我们来分析一下Python虚拟机是如何创建包含元素的字典对象和列表对象
首先是字典对象:
d = {"1": 1, "2": 2}
//分析结果
1 12 BUILD_MAP 0
15 DUP_TOP
16 LOAD_CONST 0 (1)
19 ROT_TWO
20 LOAD_CONST 2 ('1')
23 STORE_SUBSCR
24 DUP_TOP
25 LOAD_CONST 3 (2)
28 ROT_TWO
29 LOAD_CONST 4 ('2')
32 STORE_SUBSCR
33 STORE_NAME 2 (d)
BUILD_MAP会创建一个空的字典,并压入运行时栈,这没什么可说的,我们看下BUILD_MAP之后的指令DUP_TOP
ceval.c
case DUP_TOP:
v = TOP();
Py_INCREF(v);
PUSH(v);
goto fast_next_opcode;
DUP_TOP会获取栈顶的元素,增加其引用,又再一次将栈顶元素压入栈中,紧接着LOAD_CONST指令又会将1这个对象压入到运行时栈,那么我们来看下前3条指令执行完毕后运行时栈和名字空间的分布:

图1-1
Python虚拟机在接下来又执行指令ROT_TWO,我们再来看一下关于这条指令所做的内容:
ceval.c
case ROT_TWO:
v = TOP();
w = SECOND();
SET_TOP(w);
SET_SECOND(v);
goto fast_next_opcode;
ROT_TWO也是调用其他宏来完成任务的,我们看一下这几条宏的指令:
ceval.c
#define TOP() (stack_pointer[-1])
#define SECOND() (stack_pointer[-2])
#define SET_TOP(v) (stack_pointer[-1] = (v))
#define SET_SECOND(v) (stack_pointer[-2] = (v))
原来ROT_TWO这条指令会取出运行时栈的第一个元素和第二个元素,然后将其位置对调,执行完ROT_TWO之后,我们再来看一下运行时栈和名字空间的分布:

图1-2
随后又执行了一条LOAD_CONST指令,将字符串'1'压入到运行时栈中,之后,又执行了STORE_SUBSCR这条指令,而正是这条指令将字符串"1"和整数值1之间的映射建立在之前的字典对象上,我们来看一下STORE_SUBSCR的内容:
case STORE_SUBSCR:
w = TOP();
v = SECOND();
u = THIRD();
STACKADJ(-3);
/* v[w] = u */
err = PyObject_SetItem(v, w, u);
Py_DECREF(u);
Py_DECREF(v);
Py_DECREF(w);
if (err == 0) continue;
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虚拟机中的一般表达式(一)中已经解释,这里不再重复
l = [1, 2]
//分析结果
4 36 LOAD_CONST 0 (1)
39 LOAD_CONST 3 (2)
42 BUILD_LIST 2
45 STORE_NAME 3 (l)
Python虚拟机中的一般表达式(二)的更多相关文章
- Python虚拟机中的一般表达式(三)
其他一般表达式 在前两章:Python虚拟机中的一般表达式(一).Python虚拟机中的一般表达式(二)中,我们介绍了Python虚拟机是怎样执行创建一个整数值对象.字符串对象.字典对象和列表对象.现 ...
- Python虚拟机中的一般表达式(一)
在Python虚拟机框架这一章中,我们通过PyEval_EvalFrameEx看到了Python虚拟机的整体框架.而这章开始,我们将了解Python虚拟机是如何完成对Python的一般表达式的执行,这 ...
- 《python解释器源码剖析》第10章--python虚拟机中的一般表达式
10.0 序 上一章中,我们通过PyEval_EvalFrameEx看到了python虚拟机的整体框架,那么这一章我们将深入到PyEval_EvalFrameEx的各个细节当中,深入剖析python的 ...
- (Python学习9)Python虚拟机中的一般表达式
1.准备工作 执行.py程序时,Python解释器对PyCodeObject的co_code存储的字节码进行解释执行,同时co_consts存储了常量,co_names存储了变量名称.用compile ...
- 《python解释器源码剖析》第11章--python虚拟机中的控制流
11.0 序 在上一章中,我们剖析了python虚拟机中的一般表达式的实现.在剖析一遍表达式是我们的流程都是从上往下顺序执行的,在执行的过程中没有任何变化.但是显然这是不够的,因为怎么能没有流程控制呢 ...
- python虚拟机中的异常流控制
异常:对程序运行中的非正常情况进行抽象.并且提供相应的语法结构和语义元素,使得程序员能够通过这些语法结构和语义元素来方便地描述异常发生时的行为. 1.Python中的异常机制: 1.1Python虚拟 ...
- 《python解释器源码剖析》第13章--python虚拟机中的类机制
13.0 序 这一章我们就来看看python中类是怎么实现的,我们知道C不是一个面向对象语言,而python却是一个面向对象的语言,那么在python的底层,是如何使用C来支持python实现面向对象 ...
- 《python解释器源码剖析》第12章--python虚拟机中的函数机制
12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python ...
- 《python源代码剖析》笔记 python虚拟机中的函数机制
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.Python虚拟机在运行函数调用时会动态地创建新的 PyFrameObject对象, 这 ...
随机推荐
- SQL Server开窗函数之OVER子句、PARTITION BY 子句
开窗函数与聚合函数一样,都是对行的集合组进行聚合计算.它用于为行定义一个窗口(这里的窗口是指运算将要操作的行的集合),它对一组值进行操作,不需要使用GROUP BY子句对数据进行分组,能够在同一行中同 ...
- EF批量插入数据耗时对比
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- SpringMVC的基础配置及视图定位
概要 记录一下搭建SpringMVC框架的步骤 视图定位也就是改变jsp在项目中的路径 一.新建javaweb项目springmvc1,在lib中导入jar包 此项目上传了GitHub,方便去下载ja ...
- mysql(数据库,sql语句,普通查询)
第1章 数据库 1.1 数据库概述 l 什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作. l 什 ...
- SQL Server 填充因子
在创建聚集索引时,表中的数据按照索引列中的值的顺序存储在数据库的数据页中.在表中插入新的数据行或更改索引列中的值时,Microsoft® SQL Server™ 2000 可能必须重新 ...
- 加载动画插件spin.js的使用随笔
背景: 在请求后台的“漫长”等待过程中,为了提升用户体验,需要一个类似 的加载动画效果,让用户明确现在处于请求过程中,而不是机子down掉或者网站死了 静态demo(未与后台交互): HTML代码如 ...
- C基础的练习集及测试答案(1-15)
练习题:注:标有(课堂)字样的为课上练习,其他为课下练习基础题(50题)1.(课堂)编写程序,输出“XXX欢迎来到动物园!”(XXX是自己的名字). //1.(课堂)编写程序,输出“XXX欢迎来到动物 ...
- SAP GUI里Screen Painter的工作原理
我们在SAP GUI里双击一个screen编号: 单击Layout按钮可以打开Screen Painter: 这背后的工作原理是什么? 是这个RFC destination在起作用: Connecti ...
- 重温Javascript(三)-继承
继承 1.原型链继承 基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针.让原型 ...
- NGUI类之间的关系架构
NGUI Drawcall 1.使用同一个altals的元素尽量放在同一个UIPanel下面,在NGUI中,它消耗的drawcall是以每个Panel为独立计算单位进行计算的. 2.如果一个UIPan ...