Algumas medições de desempenho, usando em timeitvez de tentar fazê-lo manualmente time.
Primeiro, o Apple 2.7.2 de 64 bits:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
Agora, python.org 3.3.0 de 64 bits:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
Aparentemente, 3.x rangerealmente é um pouco mais lento do que 2.x xrange. E a xrangefunção do OP não tem nada a ver com isso. (Não é surpresa, uma vez que uma chamada única para o __iter__slot provavelmente não será visível entre 10000000 chamadas para o que acontecer no loop, mas alguém a abordou como uma possibilidade.)
Mas é apenas 30% mais lento. Como o OP ficou 2x mais lento? Bem, se eu repetir os mesmos testes com o Python de 32 bits, recebo 1,58 vs. 3,12. Então, meu palpite é que esse é mais um daqueles casos em que o 3.x foi otimizado para desempenho de 64 bits de maneiras que prejudicam 32 bits.
Mas isso realmente importa? Verifique isso com o 3.3.0 de 64 bits novamente:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Portanto, a construção do listleva mais que o dobro do tempo da iteração inteira.
E quanto a "consome muito mais recursos que o Python 2.6+", nos meus testes, parece que um 3.x rangeé exatamente do mesmo tamanho que um 2.x xrange- e, mesmo que fosse 10 vezes maior, cria a lista desnecessária ainda é 10000000x mais problemático do que qualquer coisa que a iteração de alcance possa fazer.
E o que dizer de um forloop explícito em vez do loop C dentro deque?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
Portanto, quase tanto tempo perdido na fordeclaração quanto no trabalho real de iterar o range.
Se você está preocupado em otimizar a iteração de um objeto de intervalo, provavelmente está procurando o lugar errado.
Enquanto isso, você continua perguntando por que xrangefoi removido, não importa quantas vezes as pessoas lhe digam a mesma coisa, mas vou repetir novamente: Não foi removido: foi renomeado para rangee o 2.x rangefoi removido.
Aqui estão algumas provas de que o rangeobjeto 3.3 é um descendente direto do xrangeobjeto 2.x (e não da rangefunção 2.x ): a origem para 3.3range e 2.7xrange . Você pode até ver o histórico de alterações (vinculado a, acredito, a alteração que substituiu a última instância da string "xrange" em qualquer lugar do arquivo).
Então, por que é mais lento?
Bem, por um lado, eles adicionaram muitos recursos novos. Por outro lado, eles fizeram todos os tipos de alterações em todo o lugar (especialmente na iteração interna) que têm efeitos colaterais menores. E havia muito trabalho para otimizar dramaticamente vários casos importantes, mesmo que às vezes pessimizasse levemente casos menos importantes. Adicione tudo isso, e não estou surpreso que iterar o rangemais rápido possível seja agora um pouco mais lento. É um daqueles casos menos importantes que ninguém jamais se importaria o suficiente para focar. É provável que ninguém tenha um caso de uso da vida real em que essa diferença de desempenho seja o ponto de acesso em seu código.
rangeno Python 3.x éxrangedo Python 2.x. Na verdade, foi o Python 2.xrangeque foi removido.