(válido somente para Python 2.x)
A função range()
Em Python, é muito comum usarmos a seguinte estrutura para realizar uma repetição baseada em um contador:
for i in range(0, 10):
print i,
A função range(x, y) gera uma lista de números inteiros de x até y (sem incluir o segundo). Assim, range(0, 10), gera a seguinte lista:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Desse modo, a variável i é iterada sobre essa lista, através da estrutura de repetição for. O trecho de código:
for i in range(0, 10):
print i,
pode ser lido como:
"Para cada elemento na lista [0,1,2,3,4,5,6,7,8,9], imprima tal elemento"
Usar range() ou xrange()? Eis a questão…
É comum ouvirmos ou lermos algum desenvolvedor Python aconselhando a utilização da função xrange() ao invés da função range(), por questões de desempenho. Mas o que é essa tal de xrange()?
A xrange() nada mais é do que uma função que pode, em muitos casos (não sempre), substituir o uso da função range(), fornecendo ainda melhor desempenho. Veja o código abaixo:
for i in xrange(0, 10):
print i,
O resultado dessa execução é o mesmo de quando utilizamos a função range(), porém, por gerar um elemento de cada vez, o código que utiliza a função xrange() apresenta um desempenho superior.
Quando executamos:
for i in range(0, 1000000000):
pass
A função range() irá imediatamente gerar uma lista contendo um bilhão de inteiros e alocar essa lista na memória. Uma lista contendo um bilhão de inteiros é capaz de encher a memória de um computador pessoal.
Já com a função xrange(), ao executarmos:
for i in xrange(0, 1000000000):
pass
Cada um dos inteiros (dos 1 bilhão) será gerado de uma vez, economizando memória e tempo de startup.
Vamos então testar o desempenho usando o módulo timeit().
A hora da verdade
junior@qwerty:~ $ python -m timeit "for i in xrange(10000000): pass"
10 loops, best of 3: 246 msec per loop
junior@qwerty:~-$ python -m timeit "for i in range(10000000): pass"
10 loops, best of 3: 342 msec per loop
Como podemos ver, o loop que utiliza a função xrange() foi quase 100 milisegundos mais rápido do que o loop que utiliza a função range(). Além disso, se fizermos uma análise de consumo de memória, veremos que a o código que utiliza a função range() utiliza uma quantidade de memória muito maior, pois gera a lista inteira antes de executar a iteração do for.
Então nunca mais vou usar o range(), certo?
Errado! Existe uma diferença fundamental entre as duas funções: a função xrange() não gera uma lista. Isso torna inviável, por exemplo, o slicing e a gravação de seu resultado como uma lista em uma variável. Vejamos:
>>> x = range(0, 10)
>>> print x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = xrange(0, 10)
>>> print y
xrange(10)
Ou seja, apesar de nos fornecer um desempenho superior ao desempenho obtido com a range(), a função xrange() não substitui a anterior em todos os seus casos.