Question Devriez-vous toujours privilégier xrange () sur range ()?


Pourquoi ou pourquoi pas?


441
2017-09-25 18:24


origine


Réponses:


Pour la performance, surtout quand vous itérez sur une large gamme, xrange() c'est généralement mieux. Cependant, il y a encore quelques cas où vous pourriez préférer range():

  • En python 3, range() Fait quoi xrange() utilisé pour faire et xrange() n'existe pas. Si vous voulez écrire du code qui fonctionnera sur Python 2 et Python 3, vous ne pouvez pas utiliser xrange().

  • range() peut effectivement être plus rapide dans certains cas - par exemple. si vous itérez plusieurs fois la même séquence. xrange() doit reconstruire l'objet entier à chaque fois, mais range() aura des objets entiers réels. (Il sera toujours pire en termes de mémoire cependant)

  • xrange() n'est pas utilisable dans tous les cas où une vraie liste est nécessaire. Par exemple, il ne prend pas en charge les tranches ou les méthodes de liste.

[Modifier] Il y a quelques messages mentionnant comment range() sera mis à jour par l'outil 2to3. Pour l'enregistrement, voici la sortie de l'exécution de l'outil sur certains exemples d'utilisations de range() et 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)

Comme vous pouvez le voir, lorsqu'il est utilisé dans une boucle for ou une compréhension, ou là où il est déjà entouré de list (), la portée reste inchangée.


430
2017-09-25 18:34



Non, ils ont tous deux leurs usages:

Utilisation xrange() en itérant, car il sauve la mémoire. Dire:

for x in xrange(1, one_zillion):

plutôt que:

for x in range(1, one_zillion):

D'un autre côté, utilisez range() si vous voulez réellement une liste de nombres.

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

129
2017-09-25 20:04



Vous devriez favoriser range() plus de xrange() seulement quand vous avez besoin d'une liste réelle. Par exemple, lorsque vous souhaitez modifier la liste renvoyée par range()ou lorsque vous souhaitez le découper Pour l'itération ou même simplement l'indexation normale, xrange() fonctionnera bien (et généralement beaucoup plus efficacement). Il y a un point où range() est un peu plus rapide que xrange() pour les très petites listes, mais en fonction de votre matériel et de divers autres détails, le seuil de rentabilité peut être le résultat de la longueur 1 ou 2; pas de quoi s'inquiéter. Préférer xrange().


42
2017-09-25 18:28



Une autre différence est que xrange () ne peut pas supporter des nombres plus grands que C ints, donc si vous voulez avoir une plage utilisant le support de nombres élevés de python, vous devez utiliser 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 n'a pas ce problème:

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)

30
2017-08-03 12:38



xrange() est plus efficace car au lieu de générer une liste d'objets, il génère simplement un objet à la fois. Au lieu de 100 entiers, et tous leurs frais généraux, et la liste pour les mettre, vous avez juste un nombre entier à la fois. Génération plus rapide, meilleure utilisation de la mémoire, code plus efficace.

Sauf si j'ai spécifiquement besoin d'une liste pour quelque chose, je préfère toujours xrange()


13
2017-09-25 18:28



range () renvoie une liste, xrange () renvoie un objet xrange.

xrange () est un peu plus rapide et un peu plus efficace en mémoire. Mais le gain n'est pas très important.

La mémoire supplémentaire utilisée par une liste n'est bien sûr pas seulement gaspillée, les listes ont plus de fonctionnalités (couper, répéter, insérer, ...). Les différences exactes peuvent être trouvées dans le Documentation. Il n'y a pas de règle absolue, utilisez ce qui est nécessaire.

Python 3.0 est toujours en développement, mais IIRC range () sera très similaire à xrange () de 2.X et list (range ()) peut être utilisé pour générer des listes.


8
2017-09-25 18:55



Je voudrais juste dire que c'est vraiment pas difficile d'obtenir un objet xrange avec la fonctionnalité de découpe et d'indexation. J'ai écrit du code qui marche très bien et est aussi rapide que xrange quand ça compte (itérations).

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)

Honnêtement, je pense que toute la question est un peu bête et xrange devrait faire tout ça de toute façon ...


5
2018-03-09 21:23



Un bon exemple donné dans le livre: Python pratique Par Magnus Lie Hetland

>>> zip(range(5), xrange(100000000))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

Je ne recommanderais pas d'utiliser range au lieu de xrange dans l'exemple précédent - bien que seuls les cinq premiers chiffres sont nécessaires, range calcule tous les nombres, et cela peut prendre beaucoup de temps. Avec xrange, ce n'est pas un problème car il ne calcule que les nombres nécessaires.

Oui, je lis la réponse de Brian: En python 3, range () est quand même un générateur et xrange () n'existe pas.


4
2017-08-17 11:57