[Tutor] am I missing another simpler structure?
Jeff Shannon
jeff at ccvcorp.com
Thu Dec 16 21:07:54 CET 2004
Blake Winton wrote:
>>>> def is_leap_year(year):
>>>> is_leap = True
>>>> try:
>>>> datetime.date(year, 2, 29)
>>>> except ValueError:
>>>> is_leap = False
>>>> return is_leap
>>>
>>>
>>> I would write
>>> def is_leap_year(year):
>>> try:
>>> datetime.date(year, 2, 29)
>>> return True
>>> except ValueError:
>>> return False
>>>
If one insists on single-return style, then I'd prefer to do it this way:
def is_leap_year(year):
try:
datetime.date(year, 2, 29)
is_leap = True
except ValueError:
is_leap = False
return is_leap
You still have to type 'is_leap' multiple times, but at least it's a
little bit more clear which conditions will result in it being True or
False.
> [...] Only having one
> return point from a function is a long-standing convention that is
> supposed to make programs easier to read/debug/optimize/prove correct.
Indeed, it is supposed (by some) to be better, and is thought by
others to sometimes make things more complicated. In the above code,
a single return point gives you one place to set breakpoints during
debugging, etc, but it also means that you introduce a new variable
that you must type at least three times, introducing multiple
opportunities for typos. As with most programming choices,
single-return has both a benefit and a cost. In some situations the
cost can be very large relative to the benefit; in others the cost is
very small. I find it best not to be too dogmatic about most such
stylistic questions -- I try to stay aware of the costs of a
particular approach, but I'll happily use it when the net effect is to
make the code simpler and more understandable.
Similar to the example that Kent later points out, in my work life I
often find myself writing functions (to use as the body of a loop)
where a number of unrelated tests must be done before proceeding with
processing. (This is actually in an old, crufty dialect of Basic, but
the same principle applies) I have a few choices in this case. I can
simply write the loop body in-line and use gotos to skip segments if
the tests fail (ew). I can write the loop body in-line and use
multiply nested if/else statements, but it can get difficult to track
what nesting level I'm at. I can use nested functions, each with just
one test in it, something like this:
def func1(data):
result = None
if test1:
result = func2(data)
return result
def func2(data):
result = None
if test2:
result = func3(data)
return result
def func3(data):
[...]
This gets pretty darn ugly to trace through, especially when I've got
six or eight different tests. Or, I can simply use multiple returns:
def func(data)
if not test1:
return
if not test2:
return
if not test3:
return
# do stuff with data...
It really does make it much simpler to track through the code, since I
don't care, later in the function, about the specific results of each
test, only about whether I should continue afterwards or not. In this
case, I'm weighing the cost of multiple returns against the cost of
multiple nestings or of using flag variables, and I find multiple
returns to be the lowest-cost option.
Jeff Shannon
Technician/Programmer
Credit International
More information about the Tutor
mailing list