Mam instrukcję if-elif-elif-else, w której w 99% przypadków wykonywana jest instrukcja else:
if something == 'this':
doThis()
elif something == 'that':
doThat()
elif something == 'there':
doThere()
else:
doThisMostOfTheTime()
Ta konstrukcja jest wykonywana bardzo dużo , ale ponieważ sprawdza każdy warunek, zanim trafi w inny, mam wrażenie, że nie jest to zbyt wydajne, nie mówiąc już o Pythonie. Z drugiej strony musi wiedzieć, czy któryś z tych warunków jest spełniony, więc i tak powinien go przetestować.
Czy ktoś wie, czy i jak można to zrobić skuteczniej, czy też jest to po prostu najlepszy możliwy sposób?
python
performance
if-statement
kramer65
źródło
źródło
sort
uruchomić łańcuch if / else ... w taki sposób, że wszystkie elementy, do których będzie pasował jeden z warunków, znajdują się na jednym końcu, a cała reszta na drugim? Jeśli tak, możesz sprawdzić, czy to jest szybsze / bardziej eleganckie, czy nie. Pamiętaj jednak, że jeśli nie ma problemu z wydajnością, jest zbyt wcześnie, aby martwić się optymalizacją.if not something.startswith("th"): doThisMostOfTheTime()
i zrobić inne porównanie welse
klauzuli.something
, czy też podobne porównania są wykonywane wielokrotnie na tej samej wartości?Odpowiedzi:
Kod...
... wygląda na to, że powinno być szybsze, ale w rzeczywistości jest wolniejsze niż
if
...elif
...else
konstrukcja, ponieważ musi wywołać funkcję, co może być znaczącym narzutem wydajności w ciasnej pętli.Rozważ te przykłady ...
1.py
2.py
3. py
4.py
... i zwróć uwagę, ile czasu procesora używają ...
... używając czasu użytkownika od
time(1)
.Opcja nr 4 wiąże się z dodatkowym narzutem pamięci polegającym na dodawaniu nowego elementu dla każdego wyraźnego chybienia klawisza, więc jeśli spodziewasz się nieograniczonej liczby wyraźnych chybień klawiszy, wybrałbym opcję nr 3, która wciąż jest znaczącym ulepszeniem oryginalna konstrukcja.
źródło
dict
jest wolniejsze, ale wtedy twoje czasy faktycznie pokazują, że jest to druga najszybsza opcja.dict.get()
jest wolniej, czyli2.py
najwolniej ze wszystkich.Stworzyłbym słownik:
Teraz użyj tylko:
Jeśli
something
nie zostanie znaleziony woptions
dictdict.get
, zwróci wartość domyślnądoThisMostOfTheTime
Niektóre porównania czasu:
Scenariusz:
Wyniki:
W
10**5
przypadku nieistniejących kluczy i 100 ważnych kluczy:Tak więc, w przypadku normalnego słownika, sprawdzanie klucza
key in options
jest tutaj najbardziej wydajnym sposobem:źródło
options = collections.defaultdict(lambda: doThisMostOfTheTime, {'this': doThis,'that' :doThat, 'there':doThere}); options[something]()
jest nieznacznie bardziej wydajny.options
dyktando, aby uniknąć jego przebudowy, przenosząc w ten sposób część (ale nie całość) logiki daleko od punktu użycia. Mimo wszystko niezła sztuczka!try: options[key]() except KeyError: doSomeThingElse()
(ponieważif key in options: options[key]()
przeszukujesz słownik dwa razykey
Czy możesz używać pypy?
Zachowanie oryginalnego kodu, ale uruchomienie go na pypy daje mi 50-krotne przyspieszenie.
CPython:
Pypy:
źródło
Oto przykład if z warunkami dynamicznymi przetłumaczonymi na słownik.
Jest to sposób, ale może nie być najbardziej pythonowy, ponieważ jest mniej czytelny dla osób nieposiadających biegle w Pythonie.
źródło
Ludzie ostrzegają
exec
ze względów bezpieczeństwa, ale to jest do tego idealny przypadek.To prosta maszyna stanowa.
źródło