Implementación y diferencia de rendimiento entre el método insert () de Python y la inserción por corte

¿Cuál es la diferencia entre insertar un elemento en una lista de python de las siguientes maneras?

myList.insert(at, myValue) myList[at:at] = [myValue] 

He realizado algunas pruebas y el rendimiento de las dos es muy similar, pero el inserto de rebanado siempre produce resultados ligeramente mejores. Mi pregunta es sobre la diferencia en la implementación y el rendimiento, no en el comportamiento.

Tenemos el mismo comportamiento, ver a continuación:

El comportamiento predeterminado es insertar el elemento en el índice dado; cada valor en el índice mayor se desplaza una posición al final.

 >>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> my_list.insert(5, 'item') >>> my_list ['a', 'b', 'c', 'd', 'e', 'item', 'f', 'g'] >>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> my_list.insert(-3, 'item') >>> my_list ['a', 'b', 'c', 'd', 'item', 'e', 'f', 'g'] 

Si la lista está vacía, el elemento se anexa normalmente.

 >>> my_list = [] >>> my_list.insert(5, 'item') >>> my_list ['item'] >>> my_list = [] >>> my_list.insert(-3, 'item') >>> my_list ['item'] 

Si el índice está fuera de los límites, el elemento se agrega al final si el índice es positivo o al principio si es negativo. No se plantea ninguna excepción.

 >>> my_list = ['a', 'b'] >>> my_list.insert(5, 'item') >>> my_list ['a', 'b', 'item'] >>> my_list = ['a', 'b'] >>> my_list.insert(-3, 'item') >>> my_list ['item', 'a', 'b'] 

Tenemos exactamente el mismo comportamiento con notación de segmento, en el caso de un rango de índices iguales:

 >>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> my_list[5:5] = ['item'] >>> my_list ['a', 'b', 'c', 'd', 'e', 'item', 'f', 'g'] >>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> my_list[-3:-3] = ['item'] >>> my_list ['a', 'b', 'c', 'd', 'item', 'e', 'f', 'g'] >>> my_list = [] >>> my_list[5:5] = ['item'] >>> my_list ['item'] >>> my_list = [] >>> my_list[-3:-3] = ['item'] >>> my_list ['item'] >>> my_list = ['a', 'b'] >>> my_list[5:5] = ['item'] >>> my_list ['a', 'b', 'item'] >>> my_list = ['a', 'b'] >>> my_list[-3:-3] = ['item'] >>> my_list ['item', 'a', 'b'] 

La notación de __setitem__() es lo mismo que llamar al __setitem__() con un objeto de __setitem__() :

 >>> my_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> my_list.__setitem__(slice(5, 5), ['item']) >>> my_list ['a', 'b', 'c', 'd', 'e', 'item', 'f', 'g'] 

Detalles de implementacion

Según la implementación CPython disponible en GitHub en https://github.com/python/cpython/blob/master/Objects/listobject.c y https://github.com/python/cpython/blob/master/Objects/listobject .c , tenemos:

El método insert() se define en la siguiente función:

 static PyObject * listinsert(PyListObject *self, PyObject *args) { Py_ssize_t i; PyObject *v; if (!PyArg_ParseTuple(args, "nO:insert", &i, &v)) return NULL; if (ins1(self, i, v) == 0) Py_RETURN_NONE; return NULL; } 

Que llama a la función ins1() , aquí está el código C:

 static int ins1(PyListObject *self, Py_ssize_t where, PyObject *v) { Py_ssize_t i, n = Py_SIZE(self); PyObject **items; if (v == NULL) { PyErr_BadInternalCall(); return -1; } if (n == PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "cannot add more objects to list"); return -1; } if (list_resize(self, n+1) < 0) return -1; if (where < 0) { where += n; if (where < 0) where = 0; } if (where > n) where = n; items = self->ob_item; for (i = n; --i >= where; ) items[i+1] = items[i]; Py_INCREF(v); items[where] = v; return 0; } 

La llamada al segmento se realiza mediante la función PyList_SetSlice() :

 int PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) { if (!PyList_Check(a)) { PyErr_BadInternalCall(); return -1; } return list_ass_slice((PyListObject *)a, ilow, ihigh, v); } 

La implementación optimizada se realiza en:

 static int list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) 

La inserción se realiza en el siguiente código:

 else if (d > 0) { /* Insert d items */ k = Py_SIZE(a); if (list_resize(a, k+d) < 0) goto Error; item = a->ob_item; memmove(&item[ihigh+d], &item[ihigh], (k - ihigh)*sizeof(PyObject *)); } for (k = 0; k < n; k++, ilow++) { PyObject *w = vitem[k]; Py_XINCREF(w); item[ilow] = w; } 

¡Espero eso ayude!