Good listing of low-level techniques, but I would like to add that both ifs and switches can signal a deficiency in the program architecture. Unless you are using switches for days of the week or other very stables cases, each switch is a place, which you need to change in order to add new option. it still may be ok if it the only place to perform dispatch, but let me point out some other useful constructs.
- Use of single dispatch, when conditions are mostly types
- Class “registrations”: See my question and my answer here . This is “poor man” interface approach. It is easy to add options afterwards even without touching the function, want to choose among option: Just add one more class and register it.
- Full-blown interfaces with zope.interface . This also make it’s possible to choose one of the options based on interface name.
These methods are good when an option chosen has non-trivial behavior.
One more way, which can be suitable in some applications, which are actively growing in genericity, is to use FSMs (finite-state machines) or even rule engines. These patterns will add a level of indirection, which will make switches or ifs unnecessary, and make the selection code declarative.
Of course, it may be overkill to add levels of indirection from the very start, but when a program grows there come a moment when many switches / ifs are too hardcoded, and development can be made faster by using more generic approaches and design patterns.