Zaintrygowany pytaniem o nieskończone pętle w Perlu: while (1) vs. dla (;;) Czy istnieje różnica prędkości? , Postanowiłem przeprowadzić podobne porównanie w Pythonie. Spodziewałem się, że kompilator wygeneruje ten sam kod bajtowy dla while(True): pass
i while(1): pass
, ale w rzeczywistości tak nie jest w pythonie2.7.
Poniższy skrypt:
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)
daje następujące wyniki:
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
Korzystanie while True
jest zauważalnie bardziej skomplikowane. Dlaczego to?
W innych kontekstach python działa tak, jakby był True
równy 1:
>>> True == 1
True
>>> True + True
2
Dlaczego while
rozróżnia te dwa?
Zauważyłem, że python3 ocenia instrukcje przy użyciu identycznych operacji:
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
Czy w pythonie3 nastąpiła zmiana w sposobie oceny wartości logicznych?
Odpowiedzi:
W Pythonie 2.x
True
nie jest słowem kluczowym, ale tylko wbudowaną stałą globalną, która jest zdefiniowana jako 1 wbool
typie. Dlatego tłumacz nadal musi załadować zawartośćTrue
. Innymi słowy,True
można ponownie przypisać:W Pythonie 3.x naprawdę staje się słowem kluczowym i prawdziwą stałą:
w ten sposób interpreter może zastąpić
while True:
pętlę nieskończoną pętlą.źródło
while 1
iwhile True
są identyczne w Pythonie 3?To nie jest całkiem w porządku
ponieważ wciąż można wyrwać się z pętli. Ale prawdą jest, że
else
klauzula takiej pętli nigdy nie byłaby dostępna w Pythonie 3. Prawdą jest również, że uproszczenie wyszukiwania wartości sprawia, że działa tak szybko, jakwhile 1
w Pythonie 2.Porównanie wydajności
Demonstrowanie różnicy w czasie dla nieco nietrywialnej pętli while:
Ustawiać
Python 2
Python 3
Wyjaśnienie
Aby wyjaśnić różnicę, w Pythonie 2:
ale w Pythonie 3:
Ponieważ
True
jest to słowo kluczowe w Pythonie 3, interpreter nie musi wyszukiwać wartości, aby zobaczyć, czy ktoś zastąpił ją inną wartością. Ale ponieważ można przypisaćTrue
inną wartość, tłumacz musi za każdym razem ją sprawdzać.Wniosek dotyczący Pythona 2
Jeśli masz zwartą, długotrwałą pętlę w Pythonie 2, prawdopodobnie powinieneś użyć
while 1:
zamiastwhile True:
.Wniosek dotyczący Pythona 3
Użyj,
while True:
jeśli nie masz warunków do wyrwania się z pętli.źródło
To jest pytanie sprzed 7 lat, na które już znalazła się świetna odpowiedź, ale błędne przekonanie w nim, które nie zostało uwzględnione w żadnej z odpowiedzi, sprawia, że może być mylące w przypadku niektórych innych pytań oznaczonych jako duplikaty.
Właściwie
while
nie robi tu nic innego. Wyróżnia1
iTrue
dokładnie tak samo, jak+
robi to przykład.Oto 2.7:
Teraz porównaj:
Emituje znak
LOAD_GLOBAL (True)
dla każdegoTrue
i optymalizator nie może nic zrobić z globalnym. Więcwhile
rozróżnia1
iTrue
z tego samego powodu co+
robi. (I==
nie rozróżnia ich, ponieważ optymalizator nie optymalizuje porównań).Teraz porównaj 3.6:
Tutaj emituje znak
LOAD_CONST (True)
dla słowa kluczowego, z którego może skorzystać optymalizator . WięcTrue + 1
nie rozróżnia, z dokładnie tego samego powoduwhile True
nie. (I==
nadal ich nie rozróżnia, ponieważ optymalizator nie optymalizuje porównań).Tymczasem, jeśli kod nie jest zoptymalizowany się, interpreter kończy się leczeniu
True
i1
dokładnie taka sama we wszystkich tych trzech przypadkach.bool
jest podklasąint
i dziedziczy większość swoich metod zint
iTrue
ma wewnętrzną wartość całkowitą 1. Czy więc wykonujeszwhile
test (__bool__
w 3.x,__nonzero__
w 2.x), porównanie (__eq__
) czy arytmetykę (__add__
), wywołujesz tę samą metodę, niezależnie od tego, czy używasz,True
czy1
.źródło