Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most efficient way of making an if-elif-elif-else statement when the else is done the most?

I've got a in if-elif-elif-else statement in which 99% of the time, the else statement is executed:

if something == 'this':     doThis() elif something == 'that':     doThat() elif something == 'there':     doThere() else:     doThisMostOfTheTime() 

This construct is done a lot, but since it goes over every condition before it hits the else I have the feeling this is not very efficient, let alone Pythonic. On the other hand, it does need to know if any of those conditions are met, so it should test it anyway.

Does anybody know if and how this could be done more efficiently or is this simply the best possible way to do it?

like image 787
kramer65 Avatar asked Jun 18 '13 10:06

kramer65


People also ask

Is Elif better than else?

so the difference is that the code always checks to see if an 'if' statement is true, checks 'elif' statements only if each 'if' and 'elif' statement above it is false, and 'else' runs only when the conditions for all attached 'if' and 'elif' statements are false.

Why is Elif better than if?

The elif is short for else if. It allows us to check for multiple expressions. If the condition for if is False , it checks the condition of the next elif block and so on. If all the conditions are False , the body of else is executed.

When should you use a Elif statement?

Use the elif condition is used to include multiple conditional expressions after the if condition or between the if and else conditions. The elif block is executed if the specified condition evaluates to True .


1 Answers

The code...

options.get(something, doThisMostOfTheTime)() 

...looks like it ought to be faster, but it's actually slower than the if ... elif ... else construct, because it has to call a function, which can be a significant performance overhead in a tight loop.

Consider these examples...

1.py

something = 'something'  for i in xrange(1000000):     if something == 'this':         the_thing = 1     elif something == 'that':         the_thing = 2     elif something == 'there':         the_thing = 3     else:         the_thing = 4 

2.py

something = 'something' options = {'this': 1, 'that': 2, 'there': 3}  for i in xrange(1000000):     the_thing = options.get(something, 4) 

3.py

something = 'something' options = {'this': 1, 'that': 2, 'there': 3}  for i in xrange(1000000):     if something in options:         the_thing = options[something]     else:         the_thing = 4 

4.py

from collections import defaultdict  something = 'something' options = defaultdict(lambda: 4, {'this': 1, 'that': 2, 'there': 3})  for i in xrange(1000000):     the_thing = options[something] 

...and note the amount of CPU time they use...

1.py: 160ms 2.py: 170ms 3.py: 110ms 4.py: 100ms 

...using the user time from time(1).

Option #4 does have the additional memory overhead of adding a new item for every distinct key miss, so if you're expecting an unbounded number of distinct key misses, I'd go with option #3, which is still a significant improvement on the original construct.

like image 53
Aya Avatar answered Sep 18 '22 08:09

Aya