Podría sumrse más rápido en las listas.

Esto es de alguna manera un seguimiento a esta pregunta.

Entonces, primero notará que no puede realizar una sum en una lista de cadenas para concatenarlas, Python le dice que use str.join en str.join lugar, y ese es un buen consejo, ya que no importa cómo use + en las cadenas, el rendimiento es malo. .

La restricción “no puede usar la sum ” no se aplica a la list , y sin embargo, itertools.chain.from_iterable es la forma preferida de realizar dicho aplanamiento de la lista.

Pero la sum(x,[]) cuando x es una lista de listas es definitivamente mala.

¿Pero debería seguir siendo así?

Comparé 3 enfoques

 import time import itertools a = [list(range(1,1000)) for _ in range(1000)] start=time.time() sum(a,[]) print(time.time()-start) start=time.time() list(itertools.chain.from_iterable(a)) print(time.time()-start) start=time.time() z=[] for s in a: z += s print(time.time()-start) 

resultados:

  • sum() en la lista de listas: 10.46647310256958. Está bien, lo sabíamos.
  • itertools.chain : 0.07705187797546387
  • sum acumulada personalizada con adición en el lugar: 0.057044029235839844 (puede ser más rápido que itertools.chain como ve)

Entonces, la sum está muy por detrás porque realiza el result = result + b lugar del result += b

Así que ahora mi pregunta:

¿Por qué la sum no puede usar este enfoque acumulativo cuando está disponible?

(Eso sería transparente para las aplicaciones ya existentes y haría posible el uso de la sum integrada para aplanar las listas de manera eficiente)

Podríamos tratar de hacer que sum () sea más inteligente, pero Alex Martelli y Guido van Rossum querían mantenerlo centrado en las sums aritméticas.

FWIW, debería obtener un rendimiento razonable con este simple código:

 result = [] for seq in mylists: result += seq 

Para su otra pregunta, “¿por qué no se puede usar este enfoque acumulativo cuando está disponible?”, Vea este comentario para builtin_sum () en Python / bltinmodule.c:

  /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. */ 
 /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. */ temp = PyNumber_Add(result, item); 

Tomado del código fuente incorporado de Python https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L2146 Línea: 2342

FWIW, podemos engañar al intérprete para que nos permita usar la sum en las cadenas al pasar una instancia de clase personalizada apropiada como el start de sum a sum .

 class Q(object): def __init__(self, data=''): self.data = str(data) def __str__(self): return self.data def __add__(self, other): return Q(self.data + str(other)) print(sum(['abc', 'def', 'ghi'], Q())) 

salida

 abcdefghi 

Por supuesto, esto es una cosa bastante tonta de hacer. 🙂