Best way to make a number of tests against an object('s attributes) with absence of switch statement?

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Mon Jun 16 05:06:58 EDT 2008


Phillip B Oldham a écrit :
> What would be the optimal/pythonic way to subject an object to a
> number of tests (based on the object's attributes) and redirect
> program flow?
> 
> Say I had the following:
> 
> pets[0] = {'name': 'fluffy', 'species': 'cat', 'size': 'small'}
> pets[1] = {'name': 'bruno', 'species': 'snake', 'size': 'small'}
> pets[2] = {'name': 'rex', 'species': 'dog', 'size': 'large'}
> 
> What I'd like to do is loop through 'pets', and test each object. Some
> of the tests I'd like to perform are:
> 
> Is the size 'small' and species not 'dog'?
> Is the species 'cat' and name 'fluffy'?
> Is the species not 'dog' or 'cat'?
> 
> In PHP I'd use a switch statement similar to the following:
> 
> foreach( $pets as $pet) {
> switch(true) {
> case ( $pet['size'] === 'small' && $pet['species'] !== 'dog' ):
> // do something
> break;
> // etc...
> }
> }
> 
> Now, I understand from a bit of googling that python doesn't have a
> switch statement, and because of this people rely on python's
> polymorphism.

You could also put it the other way round : Python doesn't have a switch 
statement because peoples use polymorphism !-)

(nb : not that my "reversed" statement is in any way more true than 
yours - but the fact is that procedural switch statement vs OO 
polymorphic dispatch is not such a new topic...)

> Thats great, but I've yet to come across a decent
> example which make a "click".
> 
> Any thoughts on how to proceed?

The braindead canonical OO solution would be to make a specific class 
for each species each implementing it's own version of do_something(). 
The problem is that it would only dispatch on species, not other 
attributes (size etc). Which is a inherent limitation of the canonical 
OO type-based single dispatch mechanism.

A more elaborate canonical OO solution would be to use the visitor 
pattern to overcome the single dispatch limitation.

A yet more elaborate (but way less canonical) solution is to use 
predicate-based dispatch (cf Philip Eby's work).

Anyway, and while each dispatch mechanism (from basic branching to 
complex predicate-based systems) has it's pros and cons, I'd first think 
twice (or more) about whether my current dispatch problem has some 
relative stability wrt/ the domain - IOW, it's structurally part of the 
domain and won't change anytime soon - or if it's one of those ad-hoc 
short-lived illogical "business rule" that is potentially subject to 
unpredictable change any other day. Because the appropriate solution 
really depends on this kind of considerations.

Now wrt/ your concrete example: truth is that, while expressed as a 
switch statement, it's in fact really a if/elif/.../, since the 
condition is not a constant (so you don't gain any performance gain from 
using a switch). So the simplest translation in Python is to use an 
if/elif/...


for pet in pets:
   if pet['size'] == 'small' and pet['species'] !== 'dog':
      // do something
   elif (other complex condition):
      // etc




More information about the Python-list mailing list