En Python (2 y 3). Cada vez que usamos el corte de lista, devuelve un nuevo objeto, por ejemplo:
l1 = [1,2,3,4]
print(id(l1))
l2 = l1[:]
print(id(l2))
Salida
>>> 140344378384464
>>> 140344378387272
Si se repite lo mismo con tupla, se devuelve el mismo objeto, por ejemplo:
t1 = (1,2,3,4)
t2 = t1[:]
print(id(t1))
print(id(t2))
Salida
>>> 140344379214896
>>> 140344379214896
Sería genial si alguien puede arrojar algo de luz sobre por qué está sucediendo esto, a lo largo de mi experiencia en Python tuve la impresión de que el segmento vacío devuelve un nuevo objeto.
Tengo entendido que está devolviendo el mismo objeto ya que las tuplas son inmutables y no tiene sentido crear una nueva copia. Pero, de nuevo, no se menciona en los documentos en ninguna parte.
l2 = tuple(iter(l1))
omite la optimizaciónPyTuple_GetSlice
se documentó de manera incorrecta después de ver su pregunta. Los documentos ahora se han solucionado (este era el problema bpo38557 ).Respuestas:
Las implementaciones son libres de devolver instancias idénticas para tipos inmutables (en CPython, a veces puede ver optimizaciones similares para cadenas y enteros). Como el objeto no se puede cambiar, no hay nada en el código de usuario que deba preocuparse si contiene una instancia única o simplemente otra referencia a una instancia existente.
Puede encontrar el cortocircuito en el código C aquí .
Este es un detalle de implementación, tenga en cuenta que pypy no hace lo mismo.
fuente
a->ob_item
es como(*a).ob_item
, es decir, obtiene el miembro llamadoob_item
desde elPyTupleObject
que está apuntando a, y el + ilow luego avanza al comienzo del segmento.Es un detalle de implementación. Debido a que las listas son mutables,
l1[:]
debe crear una copia, ya que no esperaría que los cambiosl2
afectenl1
.Sin embargo, dado que una tupla es inmutable , no hay nada que pueda hacer
t2
que afectet1
de manera visible, por lo que el compilador es libre (pero no obligatorio ) de usar el mismo objeto parat1
yt1[:]
.fuente
En Python 3. *
my_list[:]
es el azúcar sintáctico paratype(my_list).__getitem__(mylist, slice_object)
donde:slice_object
es un objeto de corte construido a partirmy_list
de los atributos (longitud) y la expresión[:]
. Los objetos que se comportan de esta manera se denominan subscriptables en el modelo de datos de Python, ver aquí . Para listas y tuplas__getitem__
es un método incorporado.En CPython, y para listas y tuplas,
__getitem__
se interpreta mediante la operación de código de bytesBINARY_SUBSCR
que se implementa para las tuplas aquí y para las listas aquí .En el caso de las tuplas, al recorrer el código, verá que en este bloque de código ,
static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item)
devolverá una referencia al mismoPyTupleObject
que obtuvo como argumento de entrada, si el elemento es de tipoPySlice
y el segmento se evalúa como la tupla completa.Ahora examina el código
static PyObject * list_subscript(PyListObject* self, PyObject* item)
y comprueba por sí mismo que, sea cual sea el segmento, siempre se devuelve un nuevo objeto de lista.fuente
start:stop
segmento en el tipo incorporadotup[:]
, incluido , no pasaBINARY_SUBSCR
. Sinstart:stop:step
embargo, el corte extendido pasa por suscripción.No estoy seguro de esto, pero parece que Python le proporciona un nuevo puntero al mismo objeto para evitar la copia, ya que las tuplas son idénticas (y dado que el objeto es una tupla, es inmutable).
fuente