open python operators containers

open - ¿Está el comportamiento de la lista de Python+= iterable documentado en alguna parte?



python documentation (4)

Ahora está documentado en Python 3.4+ y Python 2.7:

4.6.3. Tipos de secuencias mutables

Las operaciones en la siguiente tabla se definen en tipos de secuencia mutables. Las collections.abc.MutableSequence ABC se proporcionan para facilitar la implementación correcta de estas operaciones en tipos de secuencia personalizados.

[Abajo] s es una instancia de un tipo de secuencia mutable, t es cualquier objeto iterable x es un objeto arbitrario que cumple con las restricciones de tipo y valor impuestas por s (por ejemplo, bytearray solo acepta números enteros que cumplen con la restricción de valor 0 <= x <= 255 ).

s.extend(t) o s += t

extiende s con el contenido de t (en su mayor parte lo mismo que s[len(s):len(s)] = t )

Así que ahora está documentado que para cualquier secuencia mutable, s , s += t es sinónimo de s.extend(t) .

Parece que en Python, list += x funciona para cualquier x iterable:

In [6]: l = [] In [7]: l += [1] In [8]: l += (2, 3) In [9]: l += xrange(5) In [10]: l Out[10]: [1, 2, 3, 0, 1, 2, 3, 4]

¿Está este comportamiento documentado en alguna parte?

Para contrastar esto con list + x , este último solo funciona si x es también una list . Esto se explica en la documentation .


De Guido van Rossum :

Funciona de la misma manera que .extend() excepto que también devuelve self . No puedo encontrar documentos explicando esto. :-(

Aquí está el código fuente relevante tomado de listobject.c :

list_inplace_concat(PyListObject *self, PyObject *other) { PyObject *result; result = listextend(self, other); if (result == NULL) return result; Py_DECREF(result); Py_INCREF(self); return (PyObject *)self; }

He planteado un informe de error para corregir la documentación: http://bugs.python.org/issue16701


No ( Guido confirma , gracias a Ashwini Chaudhary). El comportamiento de += para las secuencias en general está subespecificado. Concluyo que no es requerido por la especificación que x + y donde x es una lista, y y alguna otra iterable sea un error (por lo que otras implementaciones podrían elegir permitirlo), y que otras implementaciones podrían restringir += para requerir homogéneos operandos

Sin embargo, las razones para no hacer esto son obvias: python en general intenta hacer lo correcto con los operandos, en lugar de requerir una igualdad de tipo rígida. El verdadero misterio es por qué no se permite la adición heterogénea con listas.

Actualización: nunca he pensado realmente en el problema de la adición no homogénea, en gran parte porque itertools.chain es prácticamente una solución completa al problema.

Los comentarios de los que están más familiarizados con las partes internas de Python son bienvenidos para explicar por qué se requiere que la adición sea homogénea. (Pregunta aquí: ¿Por qué la adición a la lista de Python debe ser homogénea? )


Para los fanáticos del rendimiento, sí, += es un poquito más rápido que extend :

>>> from timeit import repeat >>> min(repeat(''a.extend((1,2,3,4,5,6,7))'', ''a=[]'')) 0.23489440699995612 >>> min(repeat(''e((1,2,3,4,5,6,7))'', ''a=[]; e = a.extend'')) 0.2214308570000867 >>> min(repeat(''a+=(1,2,3,4,5,6,7)'', ''a=[]'')) 0.21909333300027356

Y aquí es cómo se compara con append :

>>> min(repeat(''a.append(1)'', ''a=[]'')) 0.062107428999297554 >>> min(repeat(''p(1)'', ''a=[]; p = a.append'')) 0.04968810399986978 >>> min(repeat(''a+=(1,)'', ''a=[]'')) 0.0501599309991434

(Pruebas en Python 3.7 de 64 bits, Windows)