Intrigué par cette question sur les boucles infinies en perl: while (1) Vs. for (;;) Y a-t-il une différence de vitesse? , J'ai décidé de lancer une comparaison similaire en python. Je m'attendais à ce que le compilateur génère le même code d'octet pour while(True): pass
et while(1): pass
, mais ce n'est en fait pas le cas en python2.7.
Le script suivant:
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)
produit les résultats suivants:
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
L'utilisation while True
est nettement plus compliquée. Pourquoi est-ce?
Dans d'autres contextes, python agit comme s'il était True
égal à 1:
>>> True == 1
True
>>> True + True
2
Pourquoi while
distingue les deux?
J'ai remarqué que python3 évalue les instructions en utilisant des opérations identiques:
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
Y a-t-il un changement dans python3 dans la façon dont les booléens sont évalués?
Réponses:
En Python 2.x, il
True
ne s'agit pas d'un mot-clé, mais simplement d'une constante globale intégrée définie à 1 dans lebool
type. Par conséquent, l'interpréteur doit toujours charger le contenu deTrue
. En d'autres termes,True
est réaffectable:En Python 3.x, cela devient vraiment un mot - clé et une vraie constante:
ainsi l'interpréteur peut remplacer la
while True:
boucle par une boucle infinie.la source
while 1
etwhile True
est identique dans Python 3?Ce n'est pas tout à fait correct,
car on peut encore sortir de la boucle. Mais il est vrai qu'une telle
else
clause de boucle ne serait jamais accessible en Python 3. Et il est également vrai qu'en simplifiant la recherche de valeur, elle s'exécute aussi rapidement quewhile 1
dans Python 2.Comparaison des performances
Démonstration de la différence de temps pour une boucle while quelque peu non triviale:
Installer
Python 2
Python 3
Explication
Pour expliquer la différence, en Python 2:
mais en Python 3:
Puisqu'il
True
s'agit d'un mot-clé dans Python 3, l'interpréteur n'a pas besoin de rechercher la valeur pour voir si quelqu'un l'a remplacée par une autre valeur. Mais comme on peut attribuerTrue
à une autre valeur, l'interprète doit la rechercher à chaque fois.Conclusion pour Python 2
Si vous avez une boucle serrée et longue dans Python 2, vous devriez probablement utiliser à la
while 1:
place dewhile True:
.Conclusion pour Python 3
À utiliser
while True:
si vous n'avez aucune condition pour sortir de votre boucle.la source
Il s'agit d'une question vieille de 7 ans qui a déjà une excellente réponse, mais une idée fausse dans la question, qui n'est abordée dans aucune des réponses, la rend potentiellement déroutante pour certaines des autres questions marquées comme des doublons.
En fait,
while
rien de différent ici du tout. Il distingue1
etTrue
exactement de la même manière que l'+
exemple.Voici 2.7:
Maintenant, comparez:
Il émet un
LOAD_GLOBAL (True)
pour chacunTrue
, et l'optimiseur ne peut rien faire avec un global. Donc,while
distingue1
etTrue
pour exactement la même raison qui le+
fait. (Et==
ne les distingue pas car l'optimiseur n'optimise pas les comparaisons.)Maintenant, comparez 3.6:
Ici, il émet un
LOAD_CONST (True)
pour le mot-clé, dont l'optimiseur peut tirer parti. Donc,True + 1
ne fait pas de distinction, pour exactement la même raisonwhile True
. (Et==
ne les distingue toujours pas car l'optimiseur n'optimise pas les comparaisons.)Pendant ce temps, si le code n'est pas optimisé, l'interpréteur finit par traiter
True
et1
exactement la même chose dans ces trois cas.bool
est une sous-classe deint
, et hérite de la plupart de ses méthodes deint
, etTrue
a une valeur entière interne de 1. Donc, que vous fassiez unwhile
test (__bool__
dans 3.x,__nonzero__
dans 2.x), une comparaison (__eq__
) ou de l'arithmétique (__add__
), vous appelez la même méthode que vous utilisiezTrue
ou1
.la source