Recentemente eu comecei a usar Python3 e é a falta de xrange dói.
Exemplo simples:
1) Python2:
from time import time as t
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print et-st
count()
2) Python3:
from time import time as t
def xrange(x):
return iter(range(x))
def count():
st = t()
[x for x in xrange(10000000) if x%4 == 0]
et = t()
print (et-st)
count()
Os resultados são, respectivamente:
1) 1.53888392448 2) 3.215819835662842
Por que é que? Quero dizer, por que xrange foi removido? É uma ótima ferramenta para aprender. Para os iniciantes, assim como eu, como todos nós estávamos em algum momento. Por que removê-lo? Alguém pode me indicar o PEP adequado, não consigo encontrá-lo.
Felicidades.
python
python-3.x
pep
xrange
catalesia
fonte
fonte
range
no Python 3.x éxrange
do Python 2.x. Na verdade, foi o Python 2.xrange
que foi removido.time
. Além de ser mais fácil de usar e mais difícil de errar, e repetir testes para você,timeit
cuida de todos os tipos de coisas que você não se lembrará, ou mesmo saberá, como cuidar (como desabilitar o GC) e pode usar um relógio com milhares de vezes melhor resolução.range
recursox%4 == 0
? Por que não apenas testarlist(xrange())
vs.list(range())
, para que haja o mínimo de trabalho estranho possível? (Por exemplo, como você sabe que o 3.x não está indox%4
mais devagar?) Por esse motivo, por que você está construindo uma enormelist
, que envolve muita alocação de memória (que, além de lenta, também é incrivelmente variável) ?iter(range)
é redundante.list(range(..))
. Isso é equivalente ao alcance do python 2. Ou, de outra forma: xrange foi renomeado como range, porque é o melhor padrão; não era necessário ter os dois, façalist(range)
se você realmente precisa de uma lista. .Respostas:
Algumas medições de desempenho, usando em
timeit
vez de tentar fazê-lo manualmentetime
.Primeiro, o Apple 2.7.2 de 64 bits:
Agora, python.org 3.3.0 de 64 bits:
Aparentemente, 3.x
range
realmente é um pouco mais lento do que 2.xxrange
. E axrange
funçã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:
Portanto, a construção do
list
leva 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.xxrange
- 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
for
loop explícito em vez do loop C dentrodeque
?Portanto, quase tanto tempo perdido na
for
declaração quanto no trabalho real de iterar orange
.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
xrange
foi removido, não importa quantas vezes as pessoas lhe digam a mesma coisa, mas vou repetir novamente: Não foi removido: foi renomeado pararange
e o 2.xrange
foi removido.Aqui estão algumas provas de que o
range
objeto 3.3 é um descendente direto doxrange
objeto 2.x (e não darange
funçã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
range
mais 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.fonte
range
. Orange
objeto em 3.3 é um descendente direto doxrange
objeto em 2.7, não darange
função em 2.7. É como perguntar enquantoitertools.imap
foi removido em favor demap
. Não há resposta, porque nada disso aconteceu.range
tempo sem fazer mais nada.O intervalo do Python3 é o xrange do Python2. Não há necessidade de envolver um iter. Para obter uma lista real no Python3, você precisa usar
list(range(...))
Se você deseja algo que funcione com Python2 e Python3, tente este
fonte
range
exrange
se comporta de maneira diferente. Não basta fazer isso, também é preciso ter certeza de nunca assumir querange
está retornando uma lista (como faria no python 2).futurize
ferramenta para converter automaticamente o seu código-fonte: python-future.org/…O
range
tipo do Python 3 funciona como o Python 2xrange
. Não sei por que você está vendo uma desaceleração, pois o iterador retornado por suaxrange
função é exatamente o que você obteria se iterasserange
diretamente.Não consigo reproduzir a desaceleração no meu sistema. Aqui está como eu testei:
Python 2, com
xrange
:Python 3, com
range
é um pouco mais rápido:Eu aprendi recentemente que o
range
tipo do Python 3 tem outros recursos interessantes, como o suporte para fatiar:range(10,100,2)[5:25:5]
isrange(20, 60, 10)
!fonte
xrange
tantas vezes, ou isso é feito apenas uma vez?xrange
foi removido, apenas renomeado .range
, no que me diz respeito, é o tempo constante__contains__
. Os novatos costumavam escrever300000 in xrange(1000000)
e isso fazia com que iterasse o todoxrange
(ou pelo menos os primeiros 30%), então tivemos que explicar por que essa era uma má ideia, mesmo que pareça tão pitônica. Agora, é pitônico.Uma maneira de corrigir seu código python2 é:
fonte
range = xrange
como está no comentário por @ John La Royxrange = range
... i mudado declaraçõesO xrange do Python 2 é um gerador e implementa o iterador, enquanto o range é apenas uma função. No Python3, não sei por que foi retirado do xrange.
fonte
range()
é o equivalente a PY2xrange()
. E, portanto, no PY3xrange()
é redundante.comp: ~ $ python Python 2.7.6 (padrão, 22 de junho de 2015, 17:58:13) [GCC 4.8.2] no linux2
5.656799077987671
5.579368829727173
21.54827117919922
22.014557123184204
Com timeit number = 1 param:
0.2245171070098877
0.10750913619995117
comp: ~ $ python3 Python 3.4.3 (padrão, 14 de outubro de 2015, 20:28:29) [GCC 4.8.4] no linux
9.113872020003328
9.07014398300089
Com timeit number = 1,2,3,4, o param funciona de maneira rápida e linear:
0.09329321900440846
0.18501482300052885
0.2703447980020428
0.36209142999723554
Parece que, se medirmos 1 ciclo de loop em execução, como timeit.timeit ("[x para x no intervalo (1000000) se x% 4]", número = 1) (como realmente usamos no código real) python3 funciona rápido o suficiente, mas em loops repetidos o python 2 xrange () vence em velocidade contra o range () do python 3.
fonte