Domanda

Perché o perché no?

È stato utile?

Soluzione

Per quanto riguarda le prestazioni, specialmente quando stai iterando su un ampio intervallo, xrange () è in genere migliore. Tuttavia, ci sono ancora alcuni casi per cui potresti preferire range () :

  • In python 3, range () fa ciò che xrange () era solito fare e xrange () non esiste. Se si desidera scrivere codice che verrà eseguito su Python 2 e Python 3, non è possibile utilizzare xrange().

  • range () può effettivamente essere più veloce in alcuni casi - ad es. se scorre ripetutamente sulla stessa sequenza. xrange () deve ricostruire l'oggetto intero ogni volta, ma range () avrà oggetti interi reali. (Andrà sempre peggio in termini di memoria)

  • xrange () non è utilizzabile in tutti i casi in cui è necessario un elenco reale. Ad esempio, non supporta le sezioni o alcun metodo di elenco.

[Modifica] Ci sono un paio di post che menzionano come range () verrà aggiornato dallo strumento 2to3. Per la cronaca, ecco l'output dell'esecuzione dello strumento su alcuni usi di esempio di range () e 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)

Come puoi vedere, quando usato in un ciclo for o comprensione, o dove è già racchiuso in list (), l'intervallo rimane invariato.

Altri suggerimenti

No, entrambi hanno i loro usi:

Usa xrange () durante l'iterazione, poiché consente di risparmiare memoria. Di ':

for x in xrange(1, one_zillion):

anziché:

for x in range(1, one_zillion):

D'altra parte, utilizzare range () se si desidera effettivamente un elenco di numeri.

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

Dovresti preferire range () su xrange () solo quando hai bisogno di un elenco reale. Ad esempio, quando si desidera modificare l'elenco restituito da range () o quando si desidera suddividerlo. Per l'iterazione o anche solo per l'indicizzazione normale, xrange () funzionerà bene (e di solito in modo molto più efficiente). C'è un punto in cui range () è un po 'più veloce di xrange () per elenchi molto piccoli, ma a seconda dell'hardware e di vari altri dettagli, il break-even può essere un risultato di lunghezza 1 o 2; non qualcosa di cui preoccuparsi. Preferisci xrange () .

Un'altra differenza è che xrange () non può supportare numeri più grandi di C ints, quindi se vuoi avere un intervallo usando il supporto per numeri grandi incorporato di Python, devi usare 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 non presenta questo 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 () è più efficiente perché invece di generare un elenco di oggetti, genera solo un oggetto alla volta. Invece di 100 numeri interi, tutti i loro costi generali e l'elenco in cui inserirli, hai solo un numero intero alla volta. Generazione più veloce, migliore utilizzo della memoria, codice più efficiente.

A meno che non abbia specificamente bisogno di un elenco per qualcosa, preferisco sempre xrange()

range () restituisce un elenco, xrange () restituisce un oggetto xrange.

xrange () è un po 'più veloce e un po' più efficiente in termini di memoria. Ma il guadagno non è molto elevato.

La memoria aggiuntiva utilizzata da un elenco ovviamente non è solo sprecata, gli elenchi hanno più funzionalità (suddivisione, ripetizione, inserimento, ...). Le differenze esatte si trovano nella documentazione . Non esiste una regola ossuta, usa ciò che è necessario.

Python 3.0 è ancora in fase di sviluppo, ma range IIRC () sarà molto simile a xrange () di 2.X e list (range ()) può essere usato per generare liste.

Vorrei solo dire che DAVVERO non è così difficile ottenere un oggetto xrange con funzionalità slice e indicizzazione. Ho scritto del codice che funziona abbastanza bene ed è veloce quanto xrange per quando conta (iterazioni).

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)

Onestamente, penso che l'intero problema sia un po 'sciocco e xrange dovrebbe fare tutto questo comunque ...

Va ??bene, tutti qui hanno un'opinione diversa riguardo ai compromessi e ai vantaggi di xrange rispetto a range. Sono per lo più corretti, xrange è un iteratore e la gamma si estende e crea un elenco reale. Nella maggior parte dei casi, non noterai davvero una differenza tra i due. (Puoi usare la mappa con range ma non con xrange, ma usa più memoria.)

Ciò che penso tu voglia sentire, è che la scelta preferita è xrange. Poiché l'intervallo in Python 3 è un iteratore, lo strumento di conversione del codice 2to3 convertirà correttamente tutti gli usi di xrange in intervallo e genererà un errore o un avviso per gli usi dell'intervallo. Se vuoi essere sicuro di convertire facilmente il tuo codice in futuro, utilizzerai solo xrange e list (xrange) quando sei sicuro di volere un elenco. L'ho imparato durante lo sprint CPython al PyCon quest'anno (2008) a Chicago.

  • range () : range (1, 10) restituisce un elenco da 1 a 10 numeri e amp; conserva l'intero elenco in memoria.
  • xrange () : come range () , ma invece di restituire un elenco, restituisce un oggetto che genera i numeri nell'intervallo su richiesta. Per il looping, questo è leggermente più veloce di range () ed è più efficiente in termini di memoria. xrange () come un iteratore e genera i numeri su richiesta (Lazy Evaluation).
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 () fa la stessa cosa di xrange () usato in Python 3 e non esiste il termine xrange () in Python 3. range () può effettivamente essere più veloce in alcuni scenari se stai ripetendo più volte la stessa sequenza. xrange () deve ricostruire l'oggetto intero ogni volta, ma range () avrà oggetti interi reali.

Mentre xrange è più veloce di range nella maggior parte dei casi, la differenza nelle prestazioni è piuttosto minima. Il piccolo programma qui sotto confronta l'iterazione su un range e 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)

I risultati seguenti mostrano che xrange è davvero più veloce, ma non abbastanza per sudare.

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

Quindi usa sempre xrange , ma a meno che tu non abbia un hardware vincolato, non preoccuparti troppo.

scroll top