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 iterablex
es un objeto arbitrario que cumple con las restricciones de tipo y valor impuestas pors
(por ejemplo,bytearray
solo acepta números enteros que cumplen con la restricción de valor0 <= x <= 255
).
s.extend(t)
os += t
extiende
s
con el contenido det
(en su mayor parte lo mismo ques[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 devuelveself
. 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)