复杂内建对象的创建

在上一章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)

  

最新文章

  1. 窥探Swift编程之别样的HelloWorld
  2. HttpContext.Current.Cache使用文件依赖问题
  3. JS学习第二课
  4. 国内顺利使用Google的另类技巧
  5. css中position:relative的真正理解
  6. 小白日记34:kali渗透测试之Web渗透-扫描工具-Burpsuite(二)
  7. bzoj1042
  8. OD: Exploit Me - Inject Instruction
  9. 【floyd存字典序路径】【HDU1385】【Minimum Transport Cost】
  10. C++中引用
  11. 关于Spring的BeanPostProcessor
  12. 谁说程序员都是苦逼的——看看兄弟连上海S2班的点点滴滴
  13. java程序的工作原理
  14. 如何在NodeJS项目中优雅的使用ES6
  15. 使用kolin开发你的android应用
  16. 分布式监控系统Zabbix--完整安装记录 -添加apache监控
  17. RedHat(Linux)下安装Python3步骤
  18. Parking Lot CodeForces - 480E
  19. Matlab 三维绘图与统计绘图
  20. Solr学习笔记之6、Solr学习资源

热门文章

  1. PreparementStatement接口
  2. mysql 中unsigned
  3. 【extjs6学习笔记】1.4 初始:ajax请求django应用
  4. 对比java和python对比
  5. ASP.NET(Web Form)绘制图表 -- Google Chart 三部曲
  6. OpenLayers 3 的 图层控制控件
  7. JS中作用域和变量提升(hoisting)的深入理解
  8. 解决nginx bind() to 0.0.0.0:80 failed 问题
  9. [论文理解]Selective Search for Object Recognition
  10. QT+event() + 事件过滤器