为什么手动字符串反转比Python 2.7中的反转更差? Slice中使用的算法是什么?

时间:2014-08-12 07:29:39

标签: python python-2.7 slice timeit

低于Slice和手动反向操作之间的性能差异。如果是这种情况,那是什么原因?

timeit.timeit("a[::-1]","a=[1,2,3,4,5,6]",number=100)
6.054327968740836e-05

timeit.timeit("[a[i] for i in range(len(a)-1,-1,-1)]","a=[1,2,3,4,5,6]",number=100)
0.0003132152330920235

3 个答案:

答案 0 :(得分:8)

这里是字节码

from dis import dis
a = [1,2,3,4,5,6]

def func1():
    a[::-1]

def func2():
    [a[i] for i in range(len(a)-1,-1,-1)]

def func3():
    reversed(a)

在第二种方法中,您可以找到长度,创建一个带范围的副本并创建变量i。

bytecode

也可以使用reverse来创建一个可迭代的。

bytecode2

答案 1 :(得分:2)

用于反转列表的切片表示法下降到C,这比反向的纯python实现要快得多。例如,在纯python方法中,python解释器必须读取,解码和执行字节代码中的每个指令,而C调用将本地执行并且不会受到这样的惩罚。这种惩罚还扩展到诸如索引项目时的方法查找等等,而在C调用中没有方法,只有地址算术。如此高效的C实现它甚至不需要专门的反向切片功能,并且仍然胜过纯python实现。相反,它会创建切片的副本并将切片反转到位(在其他地方完成)。

List slice code for cpython

static PyObject *
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
    PyListObject *np;
    PyObject **src, **dest;
    Py_ssize_t i, len;
    if (ilow < 0)
        ilow = 0;
    else if (ilow > Py_SIZE(a))
        ilow = Py_SIZE(a);
    if (ihigh < ilow)
        ihigh = ilow;
    else if (ihigh > Py_SIZE(a))
        ihigh = Py_SIZE(a);
    len = ihigh - ilow;
    np = (PyListObject *) PyList_New(len);
    if (np == NULL)
        return NULL;

    src = a->ob_item + ilow;
    dest = np->ob_item;
    for (i = 0; i < len; i++) {
        PyObject *v = src[i];
        Py_INCREF(v);
        dest[i] = v;
    }
    return (PyObject *)np;
}

答案 2 :(得分:0)

3种不同版本的反汇编 - (无屏幕截图):

import dis

a = [1,2,3,4,5,6]

def x( l ):
    return l[::-1]

dis.dis(x)
2           0 LOAD_FAST                0 (l)
            3 LOAD_CONST               0 (None)
            6 LOAD_CONST               0 (None)
            9 LOAD_CONST               1 (-1)
           12 BUILD_SLICE              3
           15 BINARY_SUBSCR       
          16 RETURN_VALUE        

def y( l ):
   return [l[i] for i in range(len(l)-1,-1,-1)]

dis.dis(y)
2           0 BUILD_LIST               0
            3 LOAD_GLOBAL              0 (range)
            6 LOAD_GLOBAL              1 (len)
            9 LOAD_FAST                0 (l)
           12 CALL_FUNCTION            1
           15 LOAD_CONST               1 (1)
           18 BINARY_SUBTRACT     
           19 LOAD_CONST               2 (-1)
           22 LOAD_CONST               2 (-1)
           25 CALL_FUNCTION            3
           28 GET_ITER            
      >>   29 FOR_ITER                16 (to 48)
           32 STORE_FAST               1 (i)
           35 LOAD_FAST                0 (l)
           38 LOAD_FAST                1 (i)
           41 BINARY_SUBSCR       
           42 LIST_APPEND              2
           45 JUMP_ABSOLUTE           29
      >>   48 RETURN_VALUE        

def z( l ):
    return [i for i in reversed(a)]

dis.dis(z)
2           0 BUILD_LIST               0
            3 LOAD_GLOBAL              0 (reversed)
            6 LOAD_GLOBAL              1 (a)
            9 CALL_FUNCTION            1
           12 GET_ITER            
      >>   13 FOR_ITER                12 (to 28)
           16 STORE_FAST               1 (i)
           19 LOAD_FAST                1 (i)
           22 LIST_APPEND              2
           25 JUMP_ABSOLUTE           13
      >>   28 RETURN_VALUE