blog
blog copied to clipboard
Python中的条件语句
if 1 > 2:
pass
elif 1 < 3:
pass
else:
pass
对应的字节码:
1 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (2)
4 COMPARE_OP 4 (>)
6 POP_JUMP_IF_FALSE 10
2 8 JUMP_FORWARD 10 (to 20)
3 >> 10 LOAD_CONST 0 (1)
12 LOAD_CONST 2 (3)
14 COMPARE_OP 0 (<)
16 POP_JUMP_IF_FALSE 20
4 18 JUMP_FORWARD 0 (to 20)
6 >> 20 LOAD_CONST 3 (None)
22 RETURN_VALUE
上一篇提到了COMPARE_OP指令最后会预判下一条指令,这里就会跳跃到PREDICTED(POP_JUMP_IF_FALSE):
#define PREDICTED(op) PRED_##op:
PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
}
POP_JUMP_IF_FALSE指令POP栈顶对象,并判断其bool值。
如果是False的话就JUMPTO跳跃到指定位置的字节码指令上。因为按照正常流程,1 > 2判断为False会进行下一个elif的判断,而这个elif判断的字节码指令的位置就是跳跃的位置。
如果判断为True就进入这个判断对应的逻辑处理,这边只有pass语句,所以没有任何字节码的产生,
下一条指令JUMP_FORWARD是结束这个判断逻辑处理:
TARGET(JUMP_FORWARD) {
JUMPBY(oparg);
FAST_DISPATCH();
}
#define JUMPBY(x) (next_instr += (x) / sizeof(_Py_CODEUNIT))
JUMP_FORWARD指令会跳跃到偏移下一条指令oparg偏移量的位置,其实就是整个if语句的末尾,这个偏移量和前面的跳跃位置都是在编译阶段就计算出来的。
至于POP_JUMP_IF_TRUE指令是在诸如if not 1 > 2这样的语句下产生的。POP_JUMP_IF_TRUE指令正好是和POP_JUMP_IF_FALSE做相反的判断跳跃。
POP_JUMP_IF_TRUE这样的指令会比产生UNARY_NOT指令+POP_JUMP_IF_FALSE指令在执行上更快。