(Pyhton学习10)Python虚拟机中的控制流

1、IF语句

a = 1
if a > 10:
    print('a > 10')
elif a<= -2:
    print('a <= -2')
else:
    print('Unkonw a')


const	:	 (1, 10, 'a > 10', 2, 'a <= -2', 'Unkonw a', None, -2)
name	:	 ('a', 'print')
  1           0 LOAD_CONST               0 (1) 
              3 STORE_NAME               0 (a) 


  2           6 LOAD_NAME                0 (a) 
              9 LOAD_CONST               1 (10) 
             12 COMPARE_OP               4 (>) 
             15 POP_JUMP_IF_FALSE       31 


  3          18 LOAD_NAME                1 (print) 
             21 LOAD_CONST               2 ('a > 10') 
             24 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             27 POP_TOP              
             28 JUMP_FORWARD            35 (to 66) 


  4     >>   31 LOAD_NAME                0 (a) 
             34 LOAD_CONST               7 (-2) 
             37 COMPARE_OP               1 (<=) 
             40 POP_JUMP_IF_FALSE       56 


  5          43 LOAD_NAME                1 (print) 
             46 LOAD_CONST               4 ('a <= -2') 
             49 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             52 POP_TOP              
             53 JUMP_FORWARD            10 (to 66) 


  7     >>   56 LOAD_NAME                1 (print) 
             59 LOAD_CONST               5 ('Unkonw a') 
             62 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             65 POP_TOP              
        >>   66 LOAD_CONST               6 (None) 
             69 RETURN_VALUE         
a = 1 不再分析。

if语句的汇编指令与《Python源码剖析》中是不同的。
if a > 10: 编译为汇编指令 LOAD_NAME LOAD_CONST COMPARE_OP POP_JUMP_IF_FALSE
需注意COMPARE_OP,分为快速通道与慢速通道,若二者皆为整数且为内置操作符,直接比较[1];否则进入慢速通道[2]。慢速通道,可以比较不同类型的对象,甚至元素与集合的关系,比如 if i in a_list。比较操作返回值为[3]Py_True或者Py_False,同样为PyObject对象。会将判断结果压入栈中。

case COMPARE_OP:
	if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
		switch (oparg) {
		case PyCmp_LT: res = a <  b; break;				// [1]
		……
		default: goto slow_compare;
		}
		x = res ? Py_True : Py_False;					// [3]
	}
	else {
	  slow_compare:
		x = cmp_outcome(oparg, v, w);					// [2]
	}
	……
	PREDICT(POP_JUMP_IF_FALSE);							// [4]
	PREDICT(POP_JUMP_IF_TRUE);
	continue;

此外, COMPARE_OP中会预测下一条指令,因为有些指令是经常一起出现的,这样可以加快执行。

#define PREDICT(op)             if (*next_instr == op) goto PRED_##op

POP_JUMP_IF_FALSE 比较简单,如果栈中的判断结果取出并判断,相符则跳转到参数所指位置[1]。
case POP_JUMP_IF_FALSE:
	w = POP();
	if (w == Py_True) {
		goto fast_next_opcode;
	}
	if (w == Py_False) {
		JUMPTO(oparg);			// [1]
		goto fast_next_opcode;
	}

print('a > 10')除去打印指令,还有 JUMP_FORWARD,跳转到if判断结束位置。
case JUMP_FORWARD:
	JUMPBY(oparg);
	goto fast_next_opcode;

2、FOR循环

l = ['efei', 'me']
for i in l:
    print(i)


const	:	 ('efei', 'me', None)
name	:	 ('l', 'i', 'print')
  1           0 LOAD_CONST               0 ('efei') 
              3 LOAD_CONST               1 ('me') 
              6 BUILD_LIST               2 
              9 STORE_NAME               0 (l) 


  2          12 SETUP_LOOP              24 (to 39) 
             15 LOAD_NAME                0 (l) 
             18 GET_ITER             
        >>   19 FOR_ITER                16 (to 38) 
             22 STORE_NAME               1 (i) 


  3          25 LOAD_NAME                2 (print) 
             28 LOAD_NAME                1 (i) 
             31 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             34 POP_TOP              
             35 JUMP_ABSOLUTE           19 
        >>   38 POP_BLOCK            
        >>   39 LOAD_CONST               2 (None) 
             42 RETURN_VALUE   

for i in l:

SETUP_LOOP,首先建立循环,用到PyFrame_BlockSetup,并且抛出异常等也是这种方式,关键是用到了PyTryBlock,并且对其进行设置,保存运行时信息,该结构体其实放到了运行时帧PyFrameObject的f_blockstack中。
case SETUP_LOOP:
case SETUP_EXCEPT:
case SETUP_FINALLY:
	PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL());
	
PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level)
{
    PyTryBlock *b;
    b = &f->f_blockstack[f->f_iblock++];
    b->b_type = type;
    b->b_level = level;
    b->b_handler = handler;
}
typedef struct {
    int b_type;			/* what kind of block this is */
    int b_handler;		/* where to jump to find handler */
    int b_level;		/* value stack level to pop to */
} PyTryBlock;

GET_ITER,然后获取迭代器。

case GET_ITER:
	x = PyObject_GetIter(v);		// 获取迭代器所指对象
	if (x != NULL) {
		SET_TOP(x);					// 压入栈中
		PREDICT(FOR_ITER);			// 预测下一条指令
		continue;
	}


PyObject_GetIter(PyObject *o) {
    PyTypeObject *t = o->ob_type;		// 指向该对象的类型对象
    getiterfunc f = NULL;			  	// 获取迭代器的函数指针
    if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER))
        f = t->tp_iter;					// 指向该类型的迭代器函数
	PyObject *res = (*f)(o);			// 获取对象
	return res;
}

Python中迭代器通过对象来实现,迭代器对象也有对应的迭代器类型。
以list对象为例,t指向PyListObject的类型PyList_Type,f指向PyList_Type中的list_iter函数。list_iter函数创建迭代器对象listiterobject it[1],it的类型为PyListIter_Type,PyListIter_Type仅实现了和iter相关的函数。
list_iter(PyObject *seq)
{
    listiterobject *it;					// [1]
    it = PyObject_GC_New(listiterobject, &PyListIter_Type);
    it->it_index = 0;					// 设置it
    it->it_seq = (PyListObject *)seq;
    _PyObject_GC_TRACK(it);
    return (PyObject *)it;				// 返回it
}
typedef struct {
    PyObject_HEAD
    long it_index;
    PyListObject *it_seq; /* Set to NULL when iterator is exhausted */
} listiterobject;
所以,GET_ITER通过某对象PyObject找到其对用类型PyXXX_Type,通过PyXXX_Type的tp_iter函数找到并创建对应类型的迭代器xxxiterobject,通过xxxiterobject指向的迭代器类型PyXXXIter_Type中的相关iter函数进行操作。
FOR_ITER,进行循环。有上述内容就比较容易理解了,最终找到相关迭代器类型的tp_iternext,返回对应对象,同时会将it_index加1,从而实现迭代器指向下一个元素。将返回的对象压入栈中,并进行预测工作,接着执行下面的打印指令。如果返回空,则直接跳转到POP_BLOCK。
case FOR_ITER:
	v = TOP();
	x = (*v->ob_type->tp_iternext)(v);			// [1]
	if (x != NULL) {
		PUSH(x);								// [2]
		PREDICT(STORE_FAST);					// [3]
		PREDICT(UNPACK_SEQUENCE);
		continue;
	}
	x = v = POP();
	Py_DECREF(v);
	JUMPBY(oparg);								// [4]
	continue;
POP_BLOCK 其实是将PyTryBlock归还给f_iblock,并将运行时栈恢复为迭代前的状态。

3、WHILE循环

while循环便很好理解了。循环初始化[1],进行比较操作[2],达到要求则执行输出[3],输出跳转到比较操作,如果不能达到要求,跳转[5]到POP_BLOCK。
i = 0
while i < 10:
    print(i)
    i += 1


const	:	 (0, 10, 1, None)
name	:	 ('i', 'print')
  1           0 LOAD_CONST               0 (0) 
              3 STORE_NAME               0 (i) 


  2           6 SETUP_LOOP              36 (to 45) 		// [1]
        >>    9 LOAD_NAME                0 (i) 			// [2]
             12 LOAD_CONST               1 (10) 
             15 COMPARE_OP               0 (<) 
             18 POP_JUMP_IF_FALSE       44 				// [5]


  3          21 LOAD_NAME                1 (print) 		// [3]
             24 LOAD_NAME                0 (i) 
             27 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             30 POP_TOP              


  4          31 LOAD_NAME                0 (i) 
             34 LOAD_CONST               2 (1) 
             37 INPLACE_ADD          
             38 STORE_NAME               0 (i) 
             41 JUMP_ABSOLUTE            9 				// [4]
        >>   44 POP_BLOCK            
        >>   45 LOAD_CONST               3 (None) 
             48 RETURN_VALUE   
			 
continue,实现很简单,直接通过JUMP_ABSOLUTE跳转到下一轮判断处[2]。
break,其实是直接将运行状态恢复到循环之后的语句,即SETUP_LOOP传入参数处。
case BREAK_LOOP:
	why = WHY_BREAK;
	goto fast_block_end;
fast_block_end:	
	if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
		why = WHY_NOT;
		JUMPTO(b->b_handler);

4、异常控制流

很重要,很复杂,还没看懂……

你可能感兴趣的:((Pyhton学习10)Python虚拟机中的控制流)