In this exercise, you'll raise a manual exception when a condition is not met in a particular function. In particular, we'll be converting birth year to age.
Specifications
One a new cell in your notebook, type the following function
import datetime
class InvalidAgeError(Exception):
pass
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
return age
Add a check that tests whether or not the person has a valid (0 or greater)
If the age is invalid, raise an InvalidAgeError
Expected Output
>>> get_age(2099)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.InvalidAgeError
My code is as following, but it shows error on raise line, how can i get expected output?
import datetime
class InvalidAgeError(Exception):
pass
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
if age >=0:
return age
else:
raise InvalidAgeError
get_age (2099)
As mentioned in the comments, your code is correct. I guess you would like to see the error message that explains why the error is raised. Here is the code for it.
def get_age(birthyear):
age = datetime.datetime.now().year - birthyear
if age >=0:
return age
else:
raise InvalidAgeError(f'InvalidAgeError: the birthyear {birthyear} exceeds the current year ({datetime.datetime.now().year})')
Please feel free to modify the Exception message the way you find appropriate.
Related
I'm having a hard time figuring out how to pass a function's return as a parameter to another function. I've searched a lot of threads that are deviations of this problem but I can't think of a solution from them. My code isn't good yet, but I just need help on the line where the error is occurring to start with.
Instructions:
create a function that asks the user to enter their birthday and returns a date object. Validate user input as well. This function must NOT take any parameters.
create another function that takes the date object as a parameter. Calculate the age of the user using their birth year and the current year.
def func1():
bd = input("When is your birthday? ")
try:
dt.datetime.strptime(bd, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYY")
except Exception as e:
print(e)
return bd
def func2(bd):
today = dt.datetime.today()
age = today.year - bd.year
return age
This is the Error I get:
TypeError: func2() missing 1 required positional argument: 'bday'
So far, I've tried:
assigning the func1 to a variable and passing the variable as func2 parameter
calling func1 inside func2
defining func1 inside func2
You're almost there, a few subtleties to consider:
The datetime object must be assigned to a variable and returned.
Your code was not assigning the datetime object, but returning a str object for input into func2. Which would have thrown an attribute error as a str has no year attribute.
Simply subtracting the years will not always give the age. What if the individual's date of birth has not yet come? In this case, 1 must be subtracted. (Notice the code update below).
For example:
from datetime import datetime as dt
def func1():
bday = input("When is your birthday? Enter as MM/DD/YYYY: ")
try:
# Assign the datetime object.
dte = dt.strptime(bday, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYYY")
except Exception as e:
print(e)
return dte # <-- Return the datetime, not a string.
def func2(bdate):
today = dt.today()
# Account for the date of birth not yet arriving.
age = today.year - bdate.year - ((today.month, today.day) < (bdate.month, bdate.day))
return age
Can be called using:
func2(bdate=func1())
I think what you want to do is use it as an argument. You can do it like this:
import datetime as dt
def func1():
bd = input("When is your birthday? ")
try:
date_object = dt.datetime.strptime(bd, "%m/%d/%Y")
except ValueError as e:
print("There is a ValueError. Please format as MM/DD/YYY")
except Exception as e:
print(e)
return date_object
def func2(bd)
today = dt.datetime.today()
age = today.year - bd.year
return age
func2(func1())
Let's try this again as my previous post wasn't that clear. I'm a newbie in Python and I'm working on a school project. However I'm stuck on a small part of code.
#Goal
Raise a ValueError when class is called with the wrong arguments.
Check argument age for float/int type and check if arguments is between 0 and 10.
Example:
class Dog():
def __init__(self, name, age):
self.name = name
def check_arg(age):
if isinstance(age, (int,float)) and age >= 0 and age <= 10:
return age
else:
raise ValueError
self.age = check_arg(age)
Now to check if it works I first put
henry = Dog("Henry", 10)
print(henry.age)
The results is printed: 10
Now I check if it is not true and put:
henry = Dog("Henry", 11)
print(henry.age)
Now I get the following:
Traceback (most recent call last):
File "c:\Folder\test.py", line 17, in
henry = Dog("Henry", 11)
File "c:\Folder\test.py", line 12, in init
self.age = check_arg(age)
File "c:\Folder\test.py", line 10, in check_arg
raise ValueError
ValueError
So it does return a ValueError, but I think the function is handling it wrong. When I return instead of raise ValueError it shows: <class 'ValueError'>
Any tips?
I wish my teacher was as fast as you guys. But he said I could ignore the traceback bit. (spend hours trying to solve this)
raise ValueError()
was correct
I need to store num_of_divisions and num_of_classes in the object School
file1.py
import file1
name_of_school=input("Enter name of Schoool\n")
printschool=f"Your School's name is {name_of_school}"
print(printschool)
try:
num_of_class=int(input("How many class are there in your School?\n"))
except (ValueError, TypeError) as okok:
print("Please Enter a valid number")
else:
if num_of_class<=0:
print("Number cannot be zero or less")
else:
printvalue=f"Number of class in school are {num_of_class}"
print(printvalue)
num_of_divisions=[]
for divisionloop in range(num_of_class):
divisionloop=divisionloop+1
num_of_divisions.append(int(input("Enter number of Divisions for class %d:"%(divisionloop))))
pak=file1.School.mouse(num_of_class, num_of_divisions)
print(pak)
fil2.py
this file below is a module
class School:
def mouse(self, num_of_class, num_of_divisions):
print(num_of_class and num_of_divisions)
self.num_of_class=num_of_class
self.num_of_divisions=num_of_divisions
return num_of_class
Error :
Traceback (most recent call last):
File "ttmain.py", line 24, in <module>
pak=classes.School.mouse(num_of_class, num_of_divisions)
TypeError: mouse() missing 1 required positional argument: 'num_of_divisions'
plus I need mouse to return value of num_of_class and num_of_divisions both
You need to create instance of your School class first and then you can access the mouse function.
schoolObj = file1.School()
return_value = schoolObj.mouse(num_of_class, num_of_divisions)
print(return_value)
I copied and pasted these lines of code from a Python tutorial book. Why does this code not work when I try to run it in PyCharm?
def inputNumber ():
x = input ('Pick a number: ')
if x == 17:
raise 'BadNumberError', '17 is a bad number'
return x
inputNumber()
This is what I got when I run the code:
Pick a number: 17
Traceback (most recent call last):
File "C:/Users/arman/Desktop/Scribble/Hello.py", line 153, in <module>
inputNumber()
File "C:/Users/arman/Desktop/Scribble/Hello.py", line 151, in inputNumber
raise 'BadNumberError', '17 is a bad number'
TypeError: exceptions must be old-style classes or derived from BaseException, not str
You can use standard exceptions:
raise ValueError('17 is a bad number')
Or you can define your own:
class BadNumberError(Exception):
pass
And then use it:
raise BadNumberError('17 is a bad number')
Just inherit from Exception class, then you can throw your own exceptions:
class BadNumberException(Exception):
pass
raise BadNumberException('17 is a bad number')
output:
Traceback (most recent call last):
File "<module1>", line 4, in <module>
BadNumberException: 17 is a bad number
If you want to define a your own error you have to do:
class BadNumberError(Exception):
pass
and then use it:
def inputNumber ():
x = input ('Pick a number: ')
if x == 17:
raise BadNumberError('17 is a bad number')
return x
inputNumber()
You should be raising exceptions as raise as follows BadNumberError('17 is a bad number') if you have already defined BadNumberError class exception.
If you haven't, then
class BadNumberError(Exception):
pass
And here is the docs with information about raising exceptions
I'd like to get detailed info about each variable treatment error.
Example 1:
user = User()
print(user.name)
...
AttributeError: variable 'user' (class User) doesn't have field 'name', there are only: full_name, address, telephone, email
Example 2:
some_nums = [1, 2, 3]
print(some_nums[3])
...
IndexError: attempt to get #4 'some_nums' list's elem; it has only 3 elems
I known i can wrap each method in my program in individual try-expect block and print such message in the except clause in each of them.
But it there any way to collect local variables data, automatically pass it to top single try-except block and print such messages there?
I saw something like in py.test library. It overrides builtin python assert's and prints detailed message in stack trace when assert falls
https://pytest.org/latest/assert.html
You can override the magic method __getattribute__ if you want to
class HelpfulErrors(object):
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except:
raise AttributeError("class {} doesn't have field '{}', there are only: {}".format(self.__class__.__name__, name, ", ".join(self.__dict__.keys())))
class User(HelpfulErrors):
def __init__(self, age=21):
self.age = age
self.can_drink = self.age >= 21
u = User()
print(u.age)
print(u.can_drink)
print(u.name)
OUTPUT
21
True
Traceback (most recent call last):
File "mes.py", line 18, in <module>
print(u.name)
File "mes.py", line 6, in __getattribute__
raise AttributeError("class {} doesn't have field '{}', there are only: {}".format(self.__class__.__name__, name, ", ".join(self.__dict__.keys())))
AttributeError: class User doesn't have field 'name', there are only: can_drink, age
This really only tells you what is currently in the classes __dict__ though, so this could change over time unless all instance members that will ever be available are defined by the time __init__ is finished.