• 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)
    

      

  • 相关阅读:
    NET Framework 4.5新特性 (二) 控制台支持 Unicode (UTF-16) 编码
    Openstack架构及配置
    MariaDB知识点总结03--从主+多主集群
    MariaDB知识点总结02--日志+备份
    Linux服务知识点总结
    MariaDB基本知识点总结01--介绍+语句
    Openstack知识点总结
    K8S知识点总结
    Docker知识点总结
    Zabbix介绍及安装(1)
  • 原文地址:https://www.cnblogs.com/beiluowuzheng/p/9462308.html
Copyright © 2020-2023  润新知