Pergunta

Por que ou por que não?

Foi útil?

Solução

Para o desempenho, especialmente quando você está iteração sobre uma grande variedade, xrange() é geralmente melhor. No entanto, ainda existem alguns casos porque você pode preferir range():

  • Em Python 3, range() faz o que xrange() usado para fazer e xrange() não existe. Se você quiser escrever código que será executado no Python 2 e Python 3, você não pode usar xrange().

  • range() pode realmente ser mais rápido em alguns casos - por exemplo. se a iteração sobre a mesma sequência de várias vezes. xrange() tem de reconstruir o objeto inteiro de cada vez, mas range() terá objectos reais inteiros. (Será sempre um desempenho pior em termos de memória no entanto)

  • xrange() não é utilizável em todos os casos em que uma lista real é necessário. Por exemplo, ele não suporta fatias, ou quaisquer métodos da lista.

[Edit] Há um par de postos de mencionar como range() será atualizado pela ferramenta 2to3. Para o registro, aqui está a saída de executar a ferramenta em alguns usos de amostra de 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)

Como você pode ver, quando usado em um loop ou compreensão, ou onde já envolvido com list (), a gama é deixado inalterado.

Outras dicas

Não, ambos têm seus usos:

Use xrange() quando a iteração, pois economiza memória. Diga:

for x in xrange(1, one_zillion):

em vez de:

for x in range(1, one_zillion):

Por outro lado, o uso range() se você realmente quer uma lista de números.

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

Você deve favorecer range() sobre xrange() somente quando você precisa de uma lista real. Por exemplo, quando você quiser modificar a lista devolvida pelo range(), ou quando você deseja cortá-lo. Para iteração ou mesmo indexação apenas normal, xrange() vai funcionar bem (e geralmente muito mais eficiente). Há um ponto onde range() é um pouco mais rápido do que xrange() para muito pequenas listas, mas dependendo do seu hardware e vários outros detalhes, o break-even pode ser em resultado de comprimento 1 ou 2; não é algo para se preocupar. Prefere xrange().

Uma outra diferença é que xrange () não pode suportar números maiores do que ints C, então se você quiser ter um usando python gama é construído em grande suporte número, você tem que faixa de uso ().

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ão tem 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() é mais eficiente porque em vez de gerar uma lista de objetos, ele só gera um objeto de cada vez. Em vez de 100 números inteiros, e todas as suas despesas, bem como a lista de colocá-los em, você só tem um número inteiro de cada vez. Faster geração, melhor uso de memória, um código mais eficiente.

A menos que eu especificamente precisa de uma lista de algo, eu sempre favorecem xrange()

gama () retorna uma lista, xrange () devolve um objecto xrange.

xrange () é um pouco mais rápido, e um pouco mais eficiente de memória. Mas o ganho não é muito grande.

A memória extra utilizado por uma lista é, naturalmente, não apenas desperdiçado, listas têm mais funcionalidade (fatia, repetição, inserção, ...). diferenças exatas podem ser encontradas no documentação . Não existe uma regra bonehard, uso o que é necessário.

Python 3.0 ainda está em desenvolvimento, mas gama IIRC () será muito semelhante ao xrange () de 2.X e lista (range ()) pode ser usado para gerar listas.

Eu gostaria apenas de dizer que ele realmente não é tão difícil de obter um objeto xrange com fatia e funcionalidade de indexação. Eu escrevi algum código que funciona bastante dang bem e é tão rápido quanto xrange para quando ele conta (iterações).

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, acho que toda a questão é uma espécie de bobo e xrange deve fazer tudo isso de qualquer maneira ...

Um exemplo bom dado no livro: Python Prático por Magnus Lie Hetland

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

Eu não recomendo o uso de intervalo em vez de xrange no exemplo anterior, embora apenas os cinco primeiros números são necessários, gama calcula todos os números, e que pode ter um monte de tempo. Com xrange, este não é um problema, porque ele calcula apenas os números necessários.

Sim eu li @ resposta de Brian: em Python 3, range () é um gerador de qualquer maneira e xrange () não existe

.

Vá com intervalo para estas razões:

1) xrange vai desaparecer em versões mais recentes do Python. Isto dá-lhe a compatibilidade fácil futuro.

2) gama vai assumir as eficiências associadas com xrange.

Ok, todo mundo aqui como uma opinião diferente quanto às vantagens e desvantagens e vantagens xrange contra alcance. Eles são principalmente correta, xrange é um iterador, e variam dá conta e cria uma lista real. Para a maioria dos casos, você não vai realmente notar a diferença entre os dois. (Você pode usar o mapa com escala mas não com xrange, mas usa mais memória.)

O que eu acho que você rali quer ouvir, no entanto, é que a escolha preferida é xrange. Desde gama em Python 3 é um iterador, a ferramenta 2to3 conversão de código converterá corretamente todos os usos de xrange a gama, e vai jogar fora um erro ou aviso para usos de gama. Se você quer ter a certeza de converter facilmente o seu código no futuro, você vai usar xrange apenas, e lista (xrange) quando tiver certeza de que deseja uma lista. Eu aprendi isso durante o sprint do CPython na PyCon este ano (2008) em Chicago.

  • range():. range(1, 10) retorna uma lista de 1 a 10 números e manter lista inteira na memória
  • xrange(): Como range(), mas em vez de retornar uma lista, retorna um objeto que gera os números no intervalo sob demanda. Para looping, este é ligeiramente mais rápido do que range() e mais eficiente de memória. objeto xrange() como um iterador e gera os números sob demanda (preguiçoso Avaliação).
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() faz a mesma coisa que xrange() costumava fazer no Python 3 e não há exist xrange() termo em Python 3. range() pode realmente ser mais rápido em algum cenário se você iteração sobre a mesma seqüência várias vezes. xrange() tem de reconstruir o objeto inteiro de cada vez, mas range() terá objectos reais inteiros.

Enquanto xrange é mais rápido que range na maioria das circunstâncias, a diferença no desempenho é mínimo. O pequeno programa abaixo compara a iteração sobre um range e um 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)

Os resultados abaixo mostra que xrange é realmente mais rápida, mas não o suficiente para suar mais.

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

Então, por todos os meios utilizar xrange, mas a menos que você estiver em um hardware restrito, não se preocupe muito com isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top