son que palabras los iteradores generadores generador funcion explicacion creacion python iterator

palabras - que es un iterable en python



¿Hay alguna forma incorporada de obtener la longitud de un iterable en python? (8)

Absolutamente no, por la sencilla razón de que no se garantiza que los iterables sean finitos.

Considere esta función de generador perfectamente legal:

def forever(): while True: yield "I will run forever"

Intentar calcular la duración de esta función con len([x for x in forever()]) claramente no funcionará.

Como ha notado, gran parte del propósito de los iteradores / generadores es poder trabajar en un gran conjunto de datos sin cargarlo todo en la memoria. El hecho de que no se puede obtener una duración inmediata se debe considerar una compensación.

Por ejemplo, los archivos, en Python, son iterables: iteran sobre las líneas en el archivo. Quiero contar el número de líneas.

Una forma rápida es hacer esto:

lines = len(list(open(fname)))

Sin embargo, esto carga todo el archivo en la memoria (a la vez). Esto más bien frustra el propósito de un iterador (que solo necesita mantener la línea actual en la memoria).

Esto no funciona:

lines = len(line for line in open(fname))

como los generadores no tienen una longitud.

¿Hay alguna manera de hacer esto sin definir una función de recuento?

def count(i): c = 0 for el in i: c += 1 return c

EDITAR: Para aclarar, ¡entiendo que todo el archivo deberá leerse! Simplemente no lo quiero en la memoria todo de una vez =).


Corto de iterar a través de iterable y contar el número de iteraciones, no. Eso es lo que lo convierte en un iterable y no en una lista. Esto no es realmente un problema específico de Python. Mire la estructura de datos de la lista enlazada clásica. Encontrar la longitud es una operación O (n) que implica iterar toda la lista para encontrar la cantidad de elementos.

Como mencionó anteriormente, probablemente pueda reducir su función a:

def count_iterable(i): return sum(1 for e in i)

Por supuesto, si está definiendo su propio objeto iterable, siempre puede implementar __len__ y mantener el conteo de un elemento en algún lugar.


He usado esta redefinición desde hace un tiempo:

def len(thingy): try: return thingy.__len__() except AttributeError: return sum(1 for item in iter(thingy))


Si lo piensas bien, ¿cómo propones que encuentres el número de líneas en un archivo sin leer el archivo completo para nuevas líneas? Claro, puede encontrar el tamaño del archivo, y si puede garantizar que la longitud de una línea es x, puede obtener el número de líneas en un archivo. Pero a menos que tengas algún tipo de restricción, no veo cómo esto puede funcionar. Además, dado que los iterables pueden ser infinitamente largos ...


Si necesita un recuento de líneas, puede hacerlo, no conozco ninguna forma mejor de hacerlo:

line_count = sum(1 for line in open("yourfile.txt"))


El paquete de cardinality proporciona una función de count() eficiente y algunas funciones relacionadas para contar y verificar el tamaño de cualquier iterable: http://cardinality.readthedocs.org/

import cardinality it = some_iterable(...) print(cardinality.count(it))

Internamente usa enumerate() y collections.deque() para mover toda la lógica real de bucle y conteo al nivel C, lo que resulta en una aceleración considerable for bucles en Python.


Resulta que hay una solución implementada para este problema común . Considere usar la función ilen() de more_itertools .

more_itertools.ilen(iterable)

Un ejemplo de impresión de varias líneas en un archivo (usamos el gestor de contexto para gestionar de forma segura los archivos de cierre):

# Example import more_itertools with open("foo.py", "r+") as f: print(more_itertools.ilen(f)) # Output: 433

Este ejemplo devuelve el mismo resultado que las soluciones presentadas anteriormente para el total de líneas en un archivo:

# Equivalent code with open("foo.py", "r+") as f: print(sum(1 for line in f)) # Output: 433


Hice una prueba entre los dos procedimientos comunes en algún código mío, que encuentra cuántos gráficos hay en n vértices, para ver qué método de conteo de elementos de una lista generada va más rápido. Sage tiene un generador de gráficos (n) que genera todos los gráficos en n vértices. Creé dos funciones que obtienen la longitud de una lista obtenida por un iterador de dos maneras diferentes y el tiempo de cada una de ellas (promediando más de 100 ejecuciones de prueba) usando la función time.time (). Las funciones fueron las siguientes:

def test_code_list(n): l = graphs(n) return len(list(l))

y

def test_code_sum(n): S = sum(1 for _ in graphs(n)) return S

Ahora yo tomo el tiempo de cada método

import time t0 = time.time() for i in range(100): test_code_list(5) t1 = time.time() avg_time = (t1-t0)/10 print ''average list method time = %s'' % avg_time t0 = time.time() for i in range(100): test_code_sum(5) t1 = time.time() avg_time = (t1-t0)/100 print "average sum method time = %s" % avg_time

promedio de tiempo de lista de métodos = 0.0391882109642

tiempo de método de suma promedio = 0.0418473792076

Entonces, al calcular el número de gráficos en n = 5 vértices de esta manera, el método de la lista es ligeramente más rápido (aunque 100 ejecuciones de prueba no es un gran tamaño de muestra). Pero cuando aumenté la longitud de la lista que se calcula intentando gráficos en n = 7 vértices (es decir, cambiando gráficos (5) a gráficos (7)), el resultado fue el siguiente:

tiempo medio del método de lista = 4.14753051996

tiempo de método de suma promedio = 3.96504004002

En este caso, el método de suma fue un poco más rápido. En general, los dos métodos son aproximadamente de la misma velocidad, pero la diferencia PUEDE depender de la longitud de su lista (también podría ser que solo promedie más de 100 carreras de prueba, que no es muy alta, habría tomado una eternidad de otra manera).