Pregunta

¿Por qué o por qué no?

¿Fue útil?

Solución

Para el rendimiento, especialmente cuando está iterando en un rango grande, xrange () suele ser mejor. Sin embargo, todavía hay algunos casos por los que puede preferir range () :

  • En Python 3, range () hace lo que xrange () solía hacer y xrange () no existe. Si desea escribir código que se ejecute tanto en Python 2 como en Python 3, no puede usar xrange().

  • range () puede ser más rápido en algunos casos, por ejemplo. si iterando sobre la misma secuencia varias veces. xrange () tiene que reconstruir el objeto entero cada vez, pero range () tendrá objetos enteros reales. (Sin embargo, siempre se desempeñará peor en términos de memoria)

  • xrange () no se puede usar en todos los casos donde se necesita una lista real. Por ejemplo, no admite segmentos, o ningún método de lista.

[Editar] Hay un par de publicaciones que mencionan cómo range () se actualizará con la herramienta 2to3. Para el registro, aquí está el resultado de ejecutar la herramienta en algunos usos de muestra de range () y xrange()

RefactoringTool: Skipping implicit fixer: buffer
RefactoringTool: Skipping implicit fixer: idioms
RefactoringTool: Skipping implicit fixer: ws_comma
--- range_test.py (original)
+++ range_test.py (refactored)
@@ -1,7 +1,7 @@

 for x in range(20):
-    a=range(20)
+    a=list(range(20))
     b=list(range(20))
     c=[x for x in range(20)]
     d=(x for x in range(20))
-    e=xrange(20)
+    e=range(20)

Como puede ver, cuando se usa en un bucle for o comprensión, o cuando ya está envuelto con list (), el rango se mantiene sin cambios.

Otros consejos

No, ambos tienen sus usos:

Use xrange () cuando esté iterando, ya que ahorra memoria. Di:

for x in xrange(1, one_zillion):

en lugar de:

for x in range(1, one_zillion):

Por otra parte, usa range () si realmente quieres una lista de números.

multiples_of_seven = range(7,100,7)
print "Multiples of seven < 100: ", multiples_of_seven

Debería favorecer range () sobre xrange () solo cuando necesite una lista real. Por ejemplo, cuando desea modificar la lista devuelta por range () , o cuando desea dividirla. Para la iteración o incluso simplemente la indexación normal, xrange () funcionará bien (y generalmente mucho más eficiente). Hay un punto donde range () es un poco más rápido que xrange () para listas muy pequeñas, pero dependiendo de su hardware y otros detalles, el punto de equilibrio puede estar en un resultado de longitud 1 o 2; No es algo de qué preocuparse. Prefiero xrange () .

Otra diferencia es que xrange () no puede admitir números más grandes que C ints, por lo tanto, si desea tener un rango utilizando Python integrado en el soporte de números grandes, debe usar range ().

Python 2.7.3 (default, Jul 13 2012, 22:29:01) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
[123456787676676767676676L, 123456787676676767676677L, 123456787676676767676678L]
>>> xrange(123456787676676767676676,123456787676676767676679)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long

Python 3 no tiene este problema:

Python 3.2.3 (default, Jul 14 2012, 01:01:48) 
[GCC 4.7.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(123456787676676767676676,123456787676676767676679)
range(123456787676676767676676, 123456787676676767676679)

xrange () es más eficiente porque en lugar de generar una lista de objetos, solo genera un objeto a la vez. En lugar de 100 enteros, y toda su sobrecarga, y la lista para ponerlos, solo tienes un entero a la vez. Generación más rápida, mejor uso de la memoria, código más eficiente.

A menos que específicamente necesite una lista para algo, siempre prefiero xrange()

range () devuelve una lista, xrange () devuelve un objeto xrange.

xrange () es un poco más rápido y un poco más eficiente en memoria. Pero la ganancia no es muy grande.

La memoria extra utilizada por una lista, por supuesto, no solo se desperdicia, las listas tienen más funciones (división, repetición, inserción, ...). Las diferencias exactas se pueden encontrar en la documentación . No hay una regla dura, usa lo que se necesita.

Python 3.0 aún está en desarrollo, pero el rango IIRC () será muy similar a xrange () de 2.X y la lista (range ()) se puede usar para generar listas.

Solo me gustaría decir que REALMENTE no es tan difícil obtener un objeto xrange con funcionalidad de división e indexación. He escrito un código que funciona bastante bien y es tan rápido como xrange para cuando cuenta (iteraciones).

from __future__ import division

def read_xrange(xrange_object):
    # returns the xrange object's start, stop, and step
    start = xrange_object[0]
    if len(xrange_object) > 1:
       step = xrange_object[1] - xrange_object[0]
    else:
        step = 1
    stop = xrange_object[-1] + step
    return start, stop, step

class Xrange(object):
    ''' creates an xrange-like object that supports slicing and indexing.
    ex: a = Xrange(20)
    a.index(10)
    will work

    Also a[:5]
    will return another Xrange object with the specified attributes

    Also allows for the conversion from an existing xrange object
    '''
    def __init__(self, *inputs):
        # allow inputs of xrange objects
        if len(inputs) == 1:
            test, = inputs
            if type(test) == xrange:
                self.xrange = test
                self.start, self.stop, self.step = read_xrange(test)
                return

        # or create one from start, stop, step
        self.start, self.step = 0, None
        if len(inputs) == 1:
            self.stop, = inputs
        elif len(inputs) == 2:
            self.start, self.stop = inputs
        elif len(inputs) == 3:
            self.start, self.stop, self.step = inputs
        else:
            raise ValueError(inputs)

        self.xrange = xrange(self.start, self.stop, self.step)

    def __iter__(self):
        return iter(self.xrange)

    def __getitem__(self, item):
        if type(item) is int:
            if item < 0:
                item += len(self)

            return self.xrange[item]

        if type(item) is slice:
            # get the indexes, and then convert to the number
            start, stop, step = item.start, item.stop, item.step
            start = start if start != None else 0 # convert start = None to start = 0
            if start < 0:
                start += start
            start = self[start]
            if start < 0: raise IndexError(item)
            step = (self.step if self.step != None else 1) * (step if step != None else 1)
            stop = stop if stop is not None else self.xrange[-1]
            if stop < 0:
                stop += stop

            stop = self[stop]
            stop = stop

            if stop > self.stop:
                raise IndexError
            if start < self.start:
                raise IndexError
            return Xrange(start, stop, step)

    def index(self, value):
        error = ValueError('object.index({0}): {0} not in object'.format(value))
        index = (value - self.start)/self.step
        if index % 1 != 0:
            raise error
        index = int(index)


        try:
            self.xrange[index]
        except (IndexError, TypeError):
            raise error
        return index

    def __len__(self):
        return len(self.xrange)

Honestamente, creo que todo el tema es un poco tonto y todo el mundo debería hacer todo esto de todos modos ...

Bien, todos aquí como una opinión diferente en cuanto a las ventajas y desventajas de xrange versus range. En su mayoría son correctos, xrange es un iterador y el rango se despliega y crea una lista real. Para la mayoría de los casos, realmente no notará una diferencia entre los dos. (Puedes usar el mapa con rango pero no con xrange, pero usa más memoria).

Sin embargo, lo que creo que quieres escuchar es que la opción preferida es xrange. Dado que el rango en Python 3 es un iterador, la herramienta de conversión de código 2to3 convertirá correctamente todos los usos de xrange en rango, y arrojará un error o advertencia para los usos de rango. Si desea asegurarse de convertir fácilmente su código en el futuro, utilizará solo xrange y lista (xrange) cuando esté seguro de que desea una lista. Aprendí esto durante el sprint de CPython en PyCon este año (2008) en Chicago.

  • range () : range (1, 10) devuelve una lista de 1 a 10 números & amp; mantener toda la lista en la memoria.
  • xrange () : Me gusta range () , pero en lugar de devolver una lista, devuelve un objeto que genera los números en el rango a pedido. Para los bucles, esto es ligeramente más rápido que range () y más eficiente en memoria. El objeto xrange () como un iterador y genera los números a pedido (Evaluación perezosa).
In [1]: range(1,10)
Out[1]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

In [2]: xrange(10)
Out[2]: xrange(10)

In [3]: print xrange.__doc__
Out[3]: xrange([start,] stop[, step]) -> xrange object

range () hace lo mismo que xrange () usado en Python 3 y no existe el término xrange () en Python 3. range () en realidad puede ser más rápido en algún escenario si se repite la misma secuencia varias veces. xrange () tiene que reconstruir el objeto entero cada vez, pero range () tendrá objetos enteros reales.

Mientras xrange es más rápido que range en la mayoría de las circunstancias, la diferencia en el rendimiento es bastante mínima. El pequeño programa a continuación compara la iteración en un range y un xrange>:

import timeit
# Try various list sizes.
for list_len in [1, 10, 100, 1000, 10000, 100000, 1000000]:
  # Time doing a range and an xrange.
  rtime = timeit.timeit('a=0;\nfor n in range(%d): a += n'%list_len, number=1000)
  xrtime = timeit.timeit('a=0;\nfor n in xrange(%d): a += n'%list_len, number=1000)
  # Print the result
  print "Loop list of len %d: range=%.4f, xrange=%.4f"%(list_len, rtime, xrtime)

Los resultados a continuación muestran que xrange es realmente más rápido, pero no lo suficiente como para sudar.

Loop list of len 1: range=0.0003, xrange=0.0003
Loop list of len 10: range=0.0013, xrange=0.0011
Loop list of len 100: range=0.0068, xrange=0.0034
Loop list of len 1000: range=0.0609, xrange=0.0438
Loop list of len 10000: range=0.5527, xrange=0.5266
Loop list of len 100000: range=10.1666, xrange=7.8481
Loop list of len 1000000: range=168.3425, xrange=155.8719

Por lo tanto, use xrange , pero a menos que esté en un hardware limitado, no se preocupe demasiado por ello.

scroll top