Control of flow

Alex Martelli aleaxit at
Tue Jul 31 09:16:13 EDT 2001

"Campbell" <cb921 at> wrote in message
news:Pine.LNX.4.31.0107311355450.2321-100000 at cb921.local...
> Hi,
> I use python to write telephony apps, and I find that a 'goto' is often
> a nice tool (stop going 'aargh', its properly "useful" sometimes =).

Naah, you can always get the same effect with better structure:-).

> Here is a little snippet that gets a month/day from a caller.  If the
> day entered is not in the range of days valid for the month entered, we
> repeat from the top.  Does anyone have a few minutes to waste helping
> me??  How better can I code things that look like this:
> >>> snip <<<
> while 1:
>     cont = 1         ## ugh!

Agreed on the "ugh" - artificial "codeflow-control" variables
ARE a horror (only marginally better than goto's:-).

>     month = getdtmf("enter2digs.vox", 2)
>     if month < 1 or month > 12:
>         play("invalidmonth.vox")
>         continue

So far so good -- and indeed 'cont' is not used here:-)

>     while 1:
>         day = getdtmf("enterday", 2)
>         if day < 1 or day > Month[month]:
>             play("invalidday.vox")
>             cont = 1
>         cont = 0

This won't work (I think you forgot a 'break' or two:-).
This loop will never exit at all.

What are the conditions under which you want to repeat
this inner loop (letting the user enter a day for the
fixed month) rather than redo the outer loop (letting
the user enter the month again)?

In general, you should move your validation code to
auxiliary functions.  Each auxiliary function can
only exit with either a valid value for whatever it
is accepting, or an indication to "redo from scratch"
(or possibly, redo from a given point, though this
may be cutting it slightly too fine:-).

For example you might have:

def getvalidated(prompt_voxfile, mysterycode,
        invalid_voxfile, lowerbound, upperbound):
    while 1:
        result = getdmf(prompt_voxfile, mysterycode)
        if lowerbound<=result<upperbound: return result

if you always wanted to keep retrying THIS part of
data-entry until the user gets it right.  This would
need no looping at the outer (application) level).

More likely, the user can also enter some code to
mean "OK, let's do it over, from scratch".  Suppose
that getdmf() is coded so that it always returns
None in that case.  Then you might use the same
convention for getvalidated, just change the if to
    if result is None or lowerbound<=result<upperbound: return result

and the upper (application) level might be:
    while 1:
        month = getvalidated("entermonth", 2,
            "invalidmonth", 1, 13)
        if month is None: continue
        day = getvalidated("enterday", 2,
            "invalidday", 1, 1+Month[month])
        if day is None: continue

that's not too bad for a couple of entries, but it
gets slightly tiresome when you have a zillion.  That
is (part of:-) what exceptions are for...

class Invalid(IOError): pass

def getvalid(prompt_voxfile, mysterycode,
        invalid_voxfile, lowerbound, upperbound):
    while 1:
        result = getdmf(prompt_voxfile, mysterycode)
        if result is None: raise Invalid
        if lowerbound<=result<upperbound: return result

and the upper application level:

    while 1:
        except Invalid: pass
        else: break

Such regularity in the code strongly suggests encoding the
changing parts (names of vox files, rules for limits) into
a data table and writing a general function to "accept a
bunch of stuff according to this table of rules", but that's
just a further helpful refactoring -- you don't *have* to
do it, it's just a possibility:-).


More information about the Python-list mailing list