Azalea-Delphinium
Azalea-Delphinium

Reputation: 19

Why is there an attribute error: int object has no attribute 'isnumeric'?

I am currently creating a program which will ask the user to enter a year and then states whether it is a leap year or not by seeing if the year is divisible by 4. It also has a type check, presence check and a length check. I keep on getting the AttributeError: 'int' object has no attribute 'isnumeric'

All in all, the program works well as I want it to (code below) but when the program has finished it states the aforementioned attribute error. Why does it display that message and how can I solve it?
Code:

print("Did you know that the last leap year was in 2020?")
print("To find out if a year is a leap year, use this program")
year = input("Please enter a year\n")
year = str(year)
valid = False

while valid == False:
  if year == "":
    print("Error. Please enter a year - it should be 4 digits long.")
    year = input("Please enter a year\n")
    year = year.decode(year)
    valid == False
  else:
    if year.isnumeric() == False:
      print("Error. Please enter a year - it should be 4 digits long.")
      year = input("Please enter a year\n")
      year = str(year)
      valid == False
    else: 
      if len(year) != 4: 
        print("Error. Please enter a year - it should be 4 digits long.")
        year = input("Please enter a year\n")
        year = str(year)
        valid == False
      else:
        year = int(year)
        rem = year%4
        if rem == 0:
           print(f"{year} is a leap year")
        else: 
           print(f"{year} is not a leap year, unfortunately")
           valid == True

Upvotes: 0

Views: 1514

Answers (1)

Samwise
Samwise

Reputation: 71424

You set year to an int here:

      else:
        year = int(year)

and then the while loop continues with code that assumes year is still a str, including this line:

  else:
    if year.isnumeric() == False:

Note that isnumeric is a method on str objects that tells you whether they contain at least one character and consist of only characters with Unicode properties Numeric_Type=Digit, Numeric_Type=Decimal, or Numeric_Type=Numeric. It is not a test for whether an object is a number, or whether a string represents a number - for example, '-1' and '1.5' report False for isnumeric. int objects are not strings, so they have no such method.

To avoid this problem, I'd suggest separating the part of the code that gets a valid year (as an int) from the part of the code that figures out whether it's a leap year:

print("Did you know that the last leap year was in 2020?")
print("To find out if a year is a leap year, use this program")

# First get the year.
while True:
    try:
        year = int(input("Please enter a year\n"))
        if len(str(year)) != 4:
           raise ValueError("wrong number of digits!")
        break
    except ValueError:
        print("Error. Please enter a year - it should be 4 digits long.")

# year is now an int with 4 digits.  Now figure out if it's leap.
if year % 4 == 0:
    print(f"{year} is a leap year")
    # Note: there is a bug here, leap year calculation
    # is actually more complicated than this!
else: 
    print(f"{year} is not a leap year, unfortunately")

Some general notes on the "get a valid int" loop and how to do this kind of thing more simply than what you tried initially:

  1. No need to convert the result of input() to a str or decode it. input only ever returns a str (in modern versions of Python -- I see you lurking there, pedants).
  2. Instead of trying to predict all the reasons that you might fail to convert a string to an int and writing a bunch of ifs to prevent them, just try the conversion and use an except to catch the ValueError that's raised on a failure. That way you only have to write one error check, and you don't need to do it by trying to reverse-engineer what some other function will do before it does it.
  3. Once you've already written a try/except, you can use a raise in the body of your try to automatically jump to the corresponding except instead of having to write the same error handling code twice.

Upvotes: 2

Related Questions