¿por qué xrange es capaz de volver al principio en Python?


He encontrado este código de La forma más pitónica de contar elementos coincidentes en algo iterable

r = xrange(1, 10)
print sum(1 for v in r if v % 2 == 0) # 4
print sum(1 for v in r if v % 3 == 0) # 3

R se itera una vez. y luego se itera de nuevo. Pensé que si un iterador se consume una vez, entonces se ha terminado y no debe ser iterado de nuevo.

Las expresiones del generador solo se pueden iterar una vez:

r = (7 * i for i in xrange(1, 10))
print sum(1 for v in r if v % 2 == 0) # 4
print sum(1 for v in r if v % 3 == 0) # 0

Enumerar (L) también:

r = enumerate(mylist)

Y el objeto file también:

f = open(myfilename, 'r')

¿Por qué xrange se comporta de manera diferente?

Author: Community, 2012-05-27

3 answers

Porque el objeto xrange producido al llamar a xrange() especifica un __iter__ que proporciona una versión única de sí mismo (en realidad, un objeto rangeiterator separado) cada vez que se itera.

>>> x = xrange(3)
>>> type(x)
<type 'xrange'>
>>> i = x.__iter__()
>>> type(i)
<type 'rangeiterator'>
 17
Author: Amber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-27 18:29:41

Porque xrange no devuelve un generador. Devuelve un objeto xrange.

>>> type(xrange(10))
<type 'xrange'>

Además de la iteración repetida, xrange los objetos soportan otras cosas que los generadores no indexing como la indexación:

>>> xrange(10)[5]
5

También tienen una longitud:

>>> len(xrange(10))
10

Y se pueden invertir:

>>> list(reversed(xrange(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

En resumen, los objetos xrange implementan la secuencia completa interfaz :

>>> import collections
>>> isinstance(xrange(10), collections.Sequence)
True

Simplemente lo hacen sin usar mucha memoria.

Tenga en cuenta también que en Python 3, el objeto range devuelto por range tiene todas las mismas propiedades.

 38
Author: senderle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-29 00:58:43

Si todo lo que sabes sobre algo es que es un iterador, entonces en general debes asumir que solo puedes iterar sobre él una vez. Eso no significa que cada iterador solo se puede consumir una vez, solo que cada iterador se puede consumir al menos una vez. El ejemplo obvio es que las listas y otras secuencias soportan esta interfaz.

Como senderle y Amber han explicado, los iteradores particulares que obtienes al llamar a xrange están implementados tal que usted puede iterar sobre ellos varias veces.

La idea general del iterador permite que los iteradores se agoten después de ser iterados. Esto se debe a que muchos iteradores (como generadores, recorrido de archivos, etc.) serían difíciles de implementar, o consumirían mucha más memoria o se ejecutarían mucho más lentamente, si tuvieran que soportar arbitrariamente muchos recorridos, y muy a menudo esta funcionalidad ni siquiera se usaría. Así que si los iteradores tuvieron que soportar arbitrariamente muchos traversals, entonces estas cosas probablemente no serían iteradores.

En resumen, si estás escribiendo código que opera en un iterador arbitrario desconocido, asumes que solo se puede recorrer una vez, y no importa si alguien te da un objeto que soporte más que la funcionalidad que necesitas. Si conoce alguna información adicional sobre el iterador (como que también es una secuencia, o incluso tanto como que es un objeto xrange), entonces puede codificar para hacer uso de eso si lo desea.

 2
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-29 01:43:12