Intrigado com esta questão sobre loops infinitos em perl: while (1) Vs. para (;;) Existe uma diferença de velocidade? , Decidi fazer uma comparação semelhante em python. Eu esperava que o compilador gerasse o mesmo código de byte para while(True): pass
e while(1): pass
, mas esse não é realmente o caso em python2.7.
O seguinte script:
import dis
def while_one():
while 1:
pass
def while_true():
while True:
pass
print("while 1")
print("----------------------------")
dis.dis(while_one)
print("while True")
print("----------------------------")
dis.dis(while_true)
produz os seguintes resultados:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 12 (to 15)
>> 3 LOAD_GLOBAL 0 (True)
6 JUMP_IF_FALSE 4 (to 13)
9 POP_TOP
9 10 JUMP_ABSOLUTE 3
>> 13 POP_TOP
14 POP_BLOCK
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
O uso while True
é visivelmente mais complicado. Por que é isso?
Em outros contextos, python age como se fosse True
igual a 1:
>>> True == 1
True
>>> True + True
2
Por que while
distingue os dois?
Percebi que o python3 avalia as instruções usando operações idênticas:
while 1
----------------------------
4 0 SETUP_LOOP 3 (to 6)
5 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
while True
----------------------------
8 0 SETUP_LOOP 3 (to 6)
9 >> 3 JUMP_ABSOLUTE 3
>> 6 LOAD_CONST 0 (None)
9 RETURN_VALUE
Há uma mudança em python3 na forma como os booleanos são avaliados?
Respostas:
No Python 2.x,
True
não é uma palavra-chave, mas apenas uma constante global integrada que é definida como 1 nobool
tipo. Portanto, o intérprete ainda precisa carregar o conteúdo deTrue
. Em outras palavras,True
é reatribuível:No Python 3.x, ele realmente se torna uma palavra-chave e uma constante real:
assim, o interpretador pode substituir o
while True:
loop por um loop infinito.fonte
while 1
ewhile True
são idênticos no Python 3?Isso não está certo,
porque ainda é possível sair do loop. Mas é verdade que essa
else
cláusula de loop nunca seria acessada no Python 3. E também é verdade que simplificar a pesquisa de valor faz com que ele seja executado tão rapidamente quantowhile 1
no Python 2.Comparação de Desempenho
Demonstrando a diferença de tempo para um loop while um tanto não trivial:
Configuração
Python 2
Python 3
Explicação
Para explicar a diferença, em Python 2:
mas em Python 3:
Como
True
é uma palavra-chave no Python 3, o interpretador não precisa consultar o valor para ver se alguém o substituiu por algum outro valor. Mas, uma vez que se pode atribuirTrue
outro valor, o intérprete deve pesquisá-lo todas as vezes.Conclusão para Python 2
Se você tiver um loop apertado e de longa execução no Python 2, provavelmente deverá usar em
while 1:
vez dewhile True:
.Conclusão para Python 3
Use
while True:
se você não tiver condições de sair do loop.fonte
Esta é uma pergunta de 7 anos que já tem uma ótima resposta, mas um equívoco na pergunta, que não foi abordado em nenhuma das respostas, a torna potencialmente confusa para algumas das outras perguntas marcadas como duplicatas.
Na verdade,
while
não está fazendo nada diferente aqui. Ele distingue1
eTrue
exatamente da mesma maneira que o+
exemplo o faz.Aqui está 2.7:
Agora compare:
Ele está emitindo um
LOAD_GLOBAL (True)
para cada umTrue
e não há nada que o otimizador possa fazer com um global. Então,while
distingue1
eTrue
pela mesma razão que+
faz. (E==
não os distingue porque o otimizador não otimiza as comparações.)Agora compare 3.6:
Aqui, ele está emitindo um
LOAD_CONST (True)
para a palavra-chave, que o otimizador pode tirar proveito. Então,True + 1
não faz distinção, exatamente pelo mesmo motivowhile True
não faz. (E==
ainda não os distingue porque o otimizador não otimiza as comparações.)Enquanto isso, se o código não for otimizado, o intérprete acaba tratando
True
e1
exatamente igual nos três casos.bool
é uma subclasse deint
e herda a maioria de seus métodos deint
eTrue
tem um valor inteiro interno de 1. Então, se você estiver fazendo umwhile
teste (__bool__
em 3.x,__nonzero__
em 2.x), uma comparação (__eq__
) ou aritmética (__add__
), você está chamando o mesmo método, quer useTrue
ou1
.fonte