[Tutor] am I missing another simpler structure?

Tim Peters tim.peters at gmail.com
Thu Dec 16 05:14:40 CET 2004


[Brian van den Broek]
> in Marc's check_range thread, I had proposed:
>
> def check_in_range(value):
> 
>     in_range = False
>     if 9 < value < 90:
>         in_range = True
>     return in_range
>
> and DogWalker suggested the better:
> 
> def check_in_range(value):
>     return 9 < value < 90
> 
> As I mentioned, I feel as though I have a mental block getting in the
> way of coming up with code in the smoother fashion of the second snippet
> above.

Don't feel frustrated -- using Boolean expressions idiomatically is
very much a learned skill.  So is adding integers, but *that* got
drilled into you over years, and years, and years.  It won't take
quite as long to sling bools <wink>.

The worst abuse is one you're perhaps not prone to:  having a Boolean
expression e, and then writing

    if e == True:

instead of

    if e:

For some reason, that's extremely common in code written by newcomers
to Pascal.  I haven't seen it nearly as often in Python code, but
don't have a theory as to why not.

> As I have been making a lot of use of a construct (pattern?)
> similar to my code above, wherein I try something, and return True if it
> works, False if it doesn't, I've begun to wonder if I am overlooking a
> improvement similar to that in DogWalker's suggestion. As an example of
> the sort of thing I have been doing:
>
> import datetime
> def is_leap_year(year):
>     '''-> boolean
> 
>     Returns True or False as year is, or is not, a leap year.
>     '''
>     is_leap = True
>     try:
>         datetime.date(year, 2, 29)
>     except ValueError:
>         is_leap = False
>     return is_leap
> 
> Please ignore that there is a function in the calendar module to do
> exactly this, and that, as that library function does, it could be done
> by simply testing if the leap year conditions are met. In the general
> case, it doesn't seem that there will always be an easy conditional
> test.

That's true!  You shouldn't work too hard to contrive one either, or
the clarity of your code will suffer.

> This function here was written so as to illustrate the structure
> I'm interested in, without the complications of the details of actual
> cases I have used.
> 
> (I hope that's clear enough--it felt much clearer before I'd spent the
> time drafting a post.)

So far as leap years go, the obvious difference is that February has
29 days in leap years, but only 28 otherwise.  You exploit that above
by checking whether trying to construct "February 29th" raises an
exception.  That's fine.  At least an equally good way is to note that
the difference between March 1 and Februrary 28 is 2 days only in a
leap year, so:

from datetime import date, timedelta
def isleap(year):
    return (date(3, 1, year) - date(2, 28, year)).days == 2

is another clear way to do it, and so is

def isleap(year):
    return (date(year, 2, 28) + timedelta(1)).month == 2

and so is

def isleap(year):
    return (date(year, 3, 1) - date(year, 2, 1)).days == 29

or even, keying off the observation that only leap years contain 366 days,

def isleap(year):
    return (date(year+1, 1, 1) - date(year, 1, 1)).days == 366

IOW, if you can think of one way to do it with a Boolean expression,
it's common to think of more.  And, of course, that's the kind of
practice that makes it feel natural, over time.


More information about the Tutor mailing list