Control of flow

Robert Amesz reqhye72zux at mailexpire.com
Tue Jul 31 19:15:25 EDT 2001


Campbell wrote:


> 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 =). 
> 
> 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!
>     month = getdtmf("enter2digs.vox", 2)
>     if month < 1 or month > 12:
>         play("invalidmonth.vox")
>         continue
>     while 1:
>         day = getdtmf("enterday", 2)
>         if day < 1 or day > Month[month]:
>             play("invalidday.vox")
>             cont = 1
>         cont = 0
>     if cont == 1:
>         continue
>     break
>>>> snip <<<

I'm not a 100% sure what this code is supposed to do, but I'll grant 
you this: it is butt-ugly, and looks like its logic is dodgy. Just look 
at the beginning and end of the loop:

while 1:
    cont = 1         ## ugh!
    <statements>
    if cont == 1:
        continue
    break


This looks fairly redundant as

cont = 1
while cont:
    <statements>  

will do *exactly* the same thing, and it's more efficient too. 
Certainly the 'ugh!' factor is reduced considerably this way.

How your app is supposed to leave the inner while 1: loop isn't clear, 
so I'll assume some crucial code has been omitted for this example.


So how would I write this code? Well, I'll assume the following 
behaviour is required:
1 - Get a valid month and day
2 - When invalid numbers are entered: start form scratch

Which yields:

while 1:
    # Get month
    month = getdtmf("enter2digs.vox", 2)
    if month < 1 or month > 12:
        play("invalidmonth.vox")
        continue     # Bad month, start from scratch

    # Get day
    day = getdtmf("enterday", 2)
    if (day >= 1) and (day <= DaysInMonth[month]):
        break        # Done!

    # Bad day...
    play("invalidday.vox")
    # ...start from scratch


[Note: I've changed the name of the 'Month'-sequence into DaysInMonth, 
because it's a better name. I presume it has been precalculated for a 
particular year, although it might be better to make it into a function 
like 
    DaysInMonth(month, year)
or
    DaysInMonth(month, isLeapYear) ]



A goto isn't needed for code like this, nor would a goto make it look 
any clearer. For more complex control flow problems it is sometimes 
advisable to break up code into separate functions and use 'return' to 
break out of those functions. Use exceptions if you need to break out 
of nested function calls.

What sometimes *does* happen is that you find that the interaction 
between the human and the machine are modelled better by a finite-state 
automaton: complex protocols are often described this way. It wouldn't 
be too hard to make a general state machine in Python, but I'll leave 
that as an excercise to the reader. ;-)


Robert Amesz



More information about the Python-list mailing list