[Tutor] re: Leap year problem

Don Arnold Don Arnold" <darnold02@sprynet.com
Sun Jan 12 16:34:05 2003


----- Original Message -----
From: "ahimsa" <ahimsa@onetel.net.uk>
To: <tutor@python.org>
Sent: Sunday, January 12, 2003 2:19 PM
Subject: [Tutor] re: Leap year problem


> Thanks to Tim, Don, and Goncalo for your input. Don your response got me
> to think about the problem and to define a function ... much more
> elegant approach. However, I still run into problems when trying to
> determine whether or not an even century is or is not a leap year. At
> present, my little program spits out that 2000 wasn't a leap year, when
> we know it was. And so again, I am stuck. Anyway, here's my code if
> someone wants to take a squizz and tell me what I could do to correct
> that false positive:
>
> _____________________________
>
> # Calculating leap years for user input:
>
> def isLeapYear(year):
>     if year % 100 == 0:                      # Error catch on first line
>         print "%s is NOT a leap year" % year
>     elif year % 400 == 0:                    # Second test
>         return 1
>     elif year % 4 == 0:                      # Third test
>         return 1
>     else:
>         print "%s is NOT a leap year" % year  # Catch everything else
>

The problem here is that the 'if ... elif ... else' construct exits as soon
as one of its conditions is met. If year is divisible by 100, it satisfies
the initial 'if' and falls through the rest of the structure, so you never
get to the later tests. If you want to structure it like this, you have to
start with the most specific test and work toward the more general ones:

def isLeapYear(year):
    if year % 400 == 0:
        return 1
    elif year % 100 == 0:
        return 0
    elif year % 4 == 0:
        return 1
    else:
        return 0

This implements the definition that Goncalo gave. To avoid having to order
your tests from specific to general, you can eliminate the elif's by
combining the conditions into a single one:

def isLeapYear2(year):
    if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
        return 1
    else:
        return 0

This is close to a word-for-word translation of the definition I gave, and
(IMO) is easier to read. Either way, the net result is the same:

year = int(raw_input('year: '))
while year != -1:
    print 'isLeapYear :', isLeapYear(year)
    print 'isLeapYear2:', isLeapYear2(year)
    print ''
    year = int(raw_input('year: '))

[begin script run]
year: 2000
isLeapYear : 1
isLeapYear2: 1

year: 1900
isLeapYear : 0
isLeapYear2: 0

year: 1996
isLeapYear : 1
isLeapYear2: 1

year: 1997
isLeapYear : 0
isLeapYear2: 0

year: -1
[end script run]


Also, it's a good idea to explicitly return 0 for false. If you don't
specify a return value, the function will return None. That works here, but
one of Python's guiding principles is 'Explicit is better than implicit'.

> leapyear = input( "Please enter a year: " )   # User input
>
> if isLeapYear(leapyear):
>     print leapyear, "is a leap year."         # Output line
>
> _____________________________________________________________________
>
> Un/fortunately, I am not doing this for a formal education course, so it
> is just for own interest and learning ... keeps me out of mischief!!!
> :-)
>

I think that's probably how most of us got started programming. If anything,
I'd say it's fortunate, since you're studying this because you're interested
in it, not just because someone is making you.

> Cheers
> Andrew
>

HTH,
Don