Today I went through some old Python code and noticed this pattern through out:
1 2 3 4 5 6 7 8 9 10 | |
This code should ideally have been a switch-case, but Python does not support a switch statement. Proponents of OOP believe that switch is bad - second only to goto. This is not strictly true - both goto and switch can be used elegantly and with great effect. Goto, for example, is great for undoing stacked changes and switch’s fall-through behavior allows nicely for ‘do things according to the stage I’m at’. However, if you’re doing OOP, consider using polymorphism instead.
I’m not doing OOP, so polymorphism does not apply to me, but I was looking for a way to optimize this code. I was on a code-cleanup spree, in the “flow”, and I thought, “Why don’t I use maps to do this?”. Brilliant! It was a really neat idea. Later I found out that this is the accepted way of doing switch-case in Python and I’d done nothing special. So anyway, the code now looked like this:
1 2 3 4 | |
And that would have been that, had I not suddenly developed a conscience. I had replaced perfectly working, mostly readable code with some other code. What if my map solution was slower? What if it was much slower? I’d done a sizable amount of refactoring, and I did not relish throwing it away. I needed to test my solution, so I wrote some sample code:
The results were disheartening. My replacement code was slower - though only just.
1 2 3 | |
I tweaked the code a little and moved the creation of the map outside of the switch_map function. Python can access local variables faster than it can access global variables, but I figured a global dict would still beat the cost of creating the dict every time.
1 2 3 | |
I breathed a sigh of relief. There was a lesson to be learnt here - test/profile before you optimize!
References and articles:
- More information about switch statements smell - c2.com
- Goto is not evil - kerneltrap.org