首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么Python会优化出"if 0",而不是"if None"?

为什么Python会优化出"if 0",而不是"if None"?
EN

Stack Overflow用户
提问于 2017-06-06 20:19:32
回答 1查看 642关注 0票数 19

为什么你编译一个像这样的条件表达式

代码语言:javascript
复制
def f():
    if None:
        print(222)
    if 0:
        print(333)

使用数字的分支得到了优化,而使用None的分支却没有?示例:

代码语言:javascript
复制
 3        0 LOAD_CONST               0 (None)
          3 POP_JUMP_IF_FALSE       14

 4        6 LOAD_CONST               1 (222)
          9 PRINT_ITEM          
         10 PRINT_NEWLINE       
         11 JUMP_FORWARD             0 (to 14)

 5  >>   14 LOAD_CONST               0 (None)
         17 RETURN_VALUE        

在哪些情况下,if 0if None的行为会有所不同?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-06 22:31:02

我的猜测是:这是一个疏忽,因为在None -2.x中,python只是一个特殊大小写的名称(或全局名称)。

如果你看一下bytecode-optimizer code in python-2.x

代码语言:javascript
复制
switch (opcode) {

   /* ... More cases ... */

        /* Replace LOAD_GLOBAL/LOAD_NAME None
           with LOAD_CONST None */
    case LOAD_NAME:
    case LOAD_GLOBAL:
        j = GETARG(codestr, i);
        name = PyString_AsString(PyTuple_GET_ITEM(names, j));
        if (name == NULL  ||  strcmp(name, "None") != 0)
            continue;
        for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) {
            if (PyList_GET_ITEM(consts, j) == Py_None)
                break;
        }
        if (j == PyList_GET_SIZE(consts)) {
            if (PyList_Append(consts, Py_None) == -1)
                goto exitError;
        }
        assert(PyList_GET_ITEM(consts, j) == Py_None);
        codestr[i] = LOAD_CONST;
        SETARG(codestr, i, j);
        cumlc = lastlc + 1;
        break;      /* Here it breaks, so it can't fall through into the next case */

        /* Skip over LOAD_CONST trueconst
           POP_JUMP_IF_FALSE xx. This improves
           "while 1" performance. */
    case LOAD_CONST:
        cumlc = lastlc + 1;
        j = GETARG(codestr, i);
        if (codestr[i+3] != POP_JUMP_IF_FALSE  ||
            !ISBASICBLOCK(blocks,i,6)  ||
            !PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
            continue;
        memset(codestr+i, NOP, 6);
        cumlc = 0;
        break;

   /* ... More cases ... */

}

您可能会注意到,None是用LOAD_GLOBALLOAD_NAME加载的,然后用LOAD_CONST替换。

但是:在它被替换之后,它会breaks,所以它不能进入LOAD_CONST的情况,在这种情况下,如果常量不是NOP,那么这个块就会被True替换。

在python-3.x中,优化器不需要特殊设置名称(或全局) None的大小写,因为它总是与LOAD_CONSTbytecode-optimizer reads一起加载

代码语言:javascript
复制
switch (opcode) {

   /* ... More cases ... */

        /* Skip over LOAD_CONST trueconst
           POP_JUMP_IF_FALSE xx.  This improves
           "while 1" performance.  */
    case LOAD_CONST:
        CONST_STACK_PUSH_OP(i);
        if (nextop != POP_JUMP_IF_FALSE  ||
            !ISBASICBLOCK(blocks, op_start, i + 1)  ||
            !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
            break;
        fill_nops(codestr, op_start, nexti + 1);
        CONST_STACK_POP(1);
        break;

   /* ... More cases ... */

}

对于LOAD_NAMELOAD_GLOBAL不再有特殊情况,因此if None (但在if False -3.x中也将if False- False设为常量)将进入LOAD_CONST情况,然后由NOP替换。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44389850

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档