Use apply() or not, and raising multiple exceptions (co-routines?)

Ype Kingma ykingma at accessforall.nl
Sun Mar 10 14:12:23 EST 2002


Roy,

You wrote:
> 
> I've got some code which performs a series of integrety checks against a
> data set.  The way I've set things up, I put each check in its own method
> and keep a list of all the methods:
> 
> checks = []
> 
> def check1 (self, data):
>    do stuff
> checks.append (check1)
> 
> def check2 (self, data):
>    do other stuff
> checks.append (check2)
> 
> and so on.  This makes it easy to add and delete bits of policy over time.
> I cycle over the checking functions by doing:
> 
> for check in self.checks:
>     check (self, data)
> 
> I could have also written this as:
> 
> for check in self.checks:
>     apply (check, [data])

Sounds familiar.

> 
> is there any particular reason to prefer one style over the other?  Having
> walked a few people through the code, I'm starting to think that the latter
> is a little more self-explanitory (especially for junior pythonistas).  On
> the other hand, I suspect it's slighly less efficient.
> 
> A related question is how best to have the check methods do more than one
> thing.  Right now, I just have each method print an error message when it
> finds a problem.  A given method might check for more than one related
> problem.  I'd like to pull the printing out of the functions themselves,
> and go to an exception based system, where I'd do something like:
> 

You might start thinking in terms of 'testing' instead of 'checking'.

> for check in self.checks:
>    try:
>       check (self, data)
>    except IntegrityCheckError, message:
>       print 'failed check:', message
> 
> The problem is I'd only catch the first problem found by a given check
> method.  The way around that would be to make the check methods each look
> for one, and only one, problem, but that wouldn't be inefficient
> (especially since some methods would share a lot of code and repeat a lot
> of work).  Is there some way to stack exceptions, so a given method can
> raise two or more of them in sequence, or something having the same effect?
> 

There is a way to do that, see below.

> The only thing I can see is to have each check method return a list of
> problems it found.  Then, the main loop would look like:
> 
> for check in self.checks:
>    for problem in check (self, data):
>       print 'failed check:', problem
> 
> but that implies pushing a lot of scaffolding down into the check methods,
> making them build and manipulate error lists to return.  I'm trying to keep
> them as clean as possible, so they're easy to write and debug.
> 

Right.

> It would be kind of neat if after doing the except clause, my method picked
> up again at the statement after the raise.  I guess what I'd have then is
> the caller and callee acting as co-routines.  Is there a way to do anything
> like that?

Definitely.

Software testers have exactly the same set of problems you describe. You test
data, but what's the difference in OO?
That's why I think you are going to really like PyUnit. It does everything you
need, and probably more. It's in the standard distribution nowadays,
but still it's wortwhile to have a look at http://pyunit.sourceforge.net/
The battery is included here:
http://www.python.org/doc/current/lib/module-unittest.html

There is a bit of learning curve, but PyUnit is really worth it.
Since you have already encountered the basic problems of designing tests
you'll probably get the point in no time. 
It will help you to let things fall into their place.

Ype



More information about the Python-list mailing list