¿Diferencia entre la división ” y ” al copiar una lista?

Podemos (superficial) copiar una list utilizando [:] :

 l = [1, 2, 3] z1 = l[:] 

También podemos (superficial) copiarlo utilizando [::] :

 z2 = l[::] 

y ahora z1 == z2 será True . Entiendo cómo funcionan estas secciones después de leer las respuestas en la notación de división de Explain Python .

Pero, mi pregunta es, ¿hay alguna diferencia entre estos dos internamente? ¿Es una copia más eficiente que la otra o hacen exactamente lo mismo?

Absolutamente ninguna diferencia entre ellos, al menos en Python 3 . Puede verificar el código de byte producido para cada uno de estos usando dis.dis si desea:

 l = [1, 2, 3, 4] 

Byte-code emitido para l[:] :

 from dis import dis dis('l[:]') 1 0 LOAD_NAME 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 BUILD_SLICE 2 12 BINARY_SUBSCR 13 RETURN_VALUE 

mientras que, byte-code emitido para l[::] :

 dis('l[::]') 1 0 LOAD_NAME 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 BUILD_SLICE 2 12 BINARY_SUBSCR 13 RETURN_VALUE 

Como puedes ver, son exactamente iguales . Ambos cargan algunos de None (los dos LOAD_CONSTS ) para los valores de start y stop utilizados para crear el segmento ( BUILD_SLICE ) y lo aplican. None es el predeterminado para estos como se indica en los documentos para los slices en la jerarquía de tipo estándar :

Atributos especiales de solo lectura: start es el límite lower ; stop es el límite superior; step es el valor de step ; cada uno es None si se omite. Estos atributos pueden tener cualquier tipo.

Usa [:] , es menos pulsaciones de teclas.


Es realmente interesante notar que en Python 2.x el código de byte generado es diferente y, debido a que hay menos comandos para l[:] , podría tener un rendimiento ligeramente mayor:

 >>> def foo(): ... l[:] ... >>> dis(foo) 2 0 LOAD_GLOBAL 0 (l) 3 SLICE+0 4 POP_TOP 5 LOAD_CONST 0 (None) 8 RETURN_VALUE 

Mientras, para l[::] :

 >>> def foo2(): ... l[::] ... >>> dis(foo2) 2 0 LOAD_GLOBAL 0 (l) 3 LOAD_CONST 0 (None) 6 LOAD_CONST 0 (None) 9 LOAD_CONST 0 (None) 12 BUILD_SLICE 3 15 BINARY_SUBSCR 16 POP_TOP 17 LOAD_CONST 0 (None) 20 RETURN_VALUE 

Aunque no los he cronometrado (y no lo haré, la diferencia debería ser pequeña), parece que, debido a que simplemente se necesitan menos instrucciones, l[:] podría ser un poco mejor.


Esta similitud no existe, por supuesto, solo para listas ; se aplica a todas las secuencias en Python:

 # Note: the Bytecode class exists in Py > 3.4 >>> from dis import Bytecode >>> >>> Bytecode('(1, 2, 3)[:]').dis() == Bytecode('(1, 2, 3)[::]').dis() True >>> Bytecode('"string"[:]').dis() == Bytecode('"string"[::]').dis() True 

similarmente para otros.

Según la sección de referencia del lenguaje Python 6.3.2, Suscripciones , la expresión interna de una secuencia debe evaluar un entero o un segmento. Ambos ejemplos producen el mismo sector y, por lo tanto, son idénticos. También hay muchos otros cortes que tienen el mismo efecto, al establecer explícitamente los valores predeterminados ( start=0 , stop=len(sequence) o más, step=1 ).