Poniżej różnicy wydajności między pokrojoną i ręczną odwrotną obsługą. Jeśli tak jest, jaki jest to powód?

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
5
logeekal 12 sierpień 2014, 11:29

3 odpowiedzi

Najlepsza odpowiedź

Oto ByteCode

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)

W drugiej metodzie znajdujesz długość, tworząc kopię z zakresem i tworzenie zmiennej I.

bytecode

Może również użyć odwrócenia, aby utworzyć iterable.

bytecode2

8
flau 12 sierpień 2014, 08:12

Plastry notation do odwracania listy spada w C, co jest znacznie szybsze niż czysta implementacja odwrotna. Na przykład, w czystym podejściu Python, tłumacz Pythona musi odczytywać, dekodować i wykonać każdą instrukcję w kodzie bajtowym, podczas gdy wezwanie C będzie wykonywać natywnie i nie cierpienia takiej kary. Ta kara rozciąga się również na takie rzeczy jak wyszukiwanie metod przy indeksowaniu przedmiotu i tak dalej, podczas gdy w połączeniu C nie ma sposobu, tylko adres arytmetyczny. Tak wydajne jest wdrożenie C, że nawet nie przejmuje się specjalistyczną odwróconą funkcją plasterków i nadal bije realizację czystego Pythona. Raczej tworzy kopię plasterka i odwrócenia plasterka na miejscu (wykonane inaczej gdzie).

Lista Kod plasterka dla Cysthon:

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
Dunes 12 sierpień 2014, 08:48

Demontaż dla 3 różnych wersji - (bez zrzutów ekranu):

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    
0
Tony Suffolk 66 12 sierpień 2014, 08:16