CSC111 Lab 9 2018
D. Thiebaut (talk) 09:54, 1 April 2018 (EDT)
This lab deals with exceptions and creating classes. The deadline for this lab is Friday 04/6/18 at 11:55 p.m.
Exceptions
Part 1: Preparation
- Create a new program called lab9_1.py, and copy this code to the new Idle window.
# lab9_1.py # Your name here # getInput: returns an integer larger # than 0. Expected to be robust def getInput(): while True: x = int( input( "Enter an integer greater than 0: " ) ) if x <= 0: print( "Invalid entry. Try again!" ) else: return x def main(): num = getInput() print( "You have entered", num ) main()
- Test it with numbers such as -3, -10, 0, 5. Verify that the input function works well when you enter numbers.
- Test your program again, and this time enter expressions such as "6.3", or "hello" (without the quotes).
- Make a note of the Error reported by Python:
- Modify your function and add the highlighted code below by hand. This code will catch the ValueError exception.
# getInput: returns an integer larger # than 0. Catches Value errors def getInput(): # repeat forever... while True: # try to get an int try: x = int( input( "Enter an integer greater than 0: " ) ) except ValueError: # the user must have entered something other than an int print( "Invalid entry. Not an integer. Try again!" ) continue # No errors caught. See if the number is negative if x <= 0: print( "You entered a negative number. Try again!" ) else: # finally, we can return x as it is an int that is >0 return x
- Run your program and try different invalid inputs, such as strings or floats. You can also try just pressing the Return key, indicating that you are not providing anything to the input function. Verify that your program catches all these invalid entries and does not crash.
Review Class Example
- Below is an example we saw in class, and that is taken from Zelle. It illustrates how we can guard some code against several types of errors. Review it. You will need to follow this example for the next set of exercises.
def ZelleExample(): import math print( "solution to quadratic equation" ) try: a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) ) disc = math.sqrt( b*b - 4*a*c ) root1 = (-b + disc )/ (2*a) root2 = (+b + disc )/ (2*a) print( "solutions: ", root1, root2 ) except NameError: print( "You didn't enter 3 numbers" ) except TypeError: print( "Your inputs were not all numbers" ) except SyntaxError: print( "Forgot commas between the numbers?" ) except ValueError: print( "No real roots, negative discriminant" ) except: print( "Something went wrong..." )
Part 2: Exercise
- Create a new program called lab9_2.py with the code below:
def example1(): for i in range( 3 ): x = int( input( "enter an integer: " ) ) y = int( input( "enter another integer: " ) ) print( x, '/', y, '=', x/y ) def example2( L ): print( "\n\nExample 2" ) sum = 0 for i in range( len( L ) ): sum += L[i] print( "sum of items in ", L, "=", sum ) def printUpperFile( fileName ): file = open( fileName, "r" ) for line in file: print( line.upper() ) file.close() def createTextFile( fileName ): file = open( fileName, "w" ) file.write( "Welcome\nto\nCSC111\nIntroduction\nto\nComp.\nSci.\n" ) file.close() def main(): # create a text file for use later... createTextFile( "csc111.txt" ) # test first function example1() # test second function L = [ 10, 3, 5, 6, 9, 3 ] example2( L ) #example2( [ 10, 3, 5, 6, "NA", 3 ] ) # test third function fileName = input( "Enter name of file to display (type csc111.txt): " ) printUpperFile( fileName ) main()
- The program above has many flaws; it is not very robust. We can easily make it crash.
- Observe each function. Run your program a few times.
- Figure out how to make each function crash
- Go ahead and start forcing the first function to crash. Register the XXXXError that is generated. For example, if the output of the crash looks like this:
Traceback (most recent call last):
File "/Users/thiebaut/Desktop/except0.py", line 29, in <module>
main()
File "/Users/thiebaut/Desktop/except0.py", line 27, in main
example3( [ 10, 3, 5, 6 ] )
File "/Users/thiebaut/Desktop/except0.py", line 18, in example3
sum = sum + L[i]
IndexError: list index out of range
- what you are interested in is IndexError. This is the exception you want to guard your code against.
try: ........ ........ except IndexError: .........
- Add the try/except statement inside the function, and verify that your function is now more robust and does not crash on the same input that made it crash before.
- Repeat the same process for the other functions.
Classes and Objects
Cats
Below is the program we saw in class, where we create a Cat class, where each cat is defined by a name, a breed, whether it is vaccinated or not, and and age.
# cats1.py # D. Thiebaut # Program for Week #9 # Define a Cat class, and # use it to create a collection of # cats. class Cat: """a class that implements a cat and its information. Name, breed, vaccinated, tattooed, and age.""" def __init__( self, na, brd, vacc, ag ): """constructor. Builds a cat with all its information""" self.name = na self.breed = brd self.vaccinated = vacc self.age = ag def isVaccinated( self ): """returns True if cat is vaccinated, False otherwise""" return self.vaccinated def getAge( self ): """returns cat's age""" return self.age def getName( self ): """returns name of cat""" return self.name def __str__( self ): """default string representation of cat""" vacc = "vaccinated" if not self.vaccinated: vacc = "not vaccinated" return "{0:20}:==> {1:1}, {2:1}, {3:1} yrs old".format( self.name, self.breed, vacc, self.age ) def main(): """ main program. Creates a list of cats and displays groups sharing the same property. Minou, 3, vac, stray Max, 1, not-vac, Burmese Gizmo, 2, vac, Bengal Garfield, 4, not-vac, Orange Tabby """ cats = [] cat = Cat( "Minou", "stray", True, 3 ) cats.append( cat ) cats.append( Cat( "Max", "Burmese", False, 1 ) ) cats.append( Cat( "Gizmo", "Bengal", True, 2 ) ) cats.append( Cat( "Garfield", "Orange Tabby", False, 4 ) ) # print the list of all the cats print( "\nComplete List:" ) for cat in cats: print( cat ) main()
- Recreate this code in a program called Lab9_2.py
- Run it.
- Add a loop to your main program that outputs only the cats that are not vaccinated, and only those.
- Example of what your output should look like:
Complete List: Minou :==> stray, vaccinated, 3 yrs old Max :==> Burmese, not vaccinated, 1 yrs old Gizmo :==> Bengal, vaccinated, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, 4 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, 4 yrs old
- Note: We will not worry about plural or singular form for "yrs old" in this lab.
Challenge #0: getBreed() method |
- Add a new method to your Cat class that returns the breed of a cat. You may want to call it getBreed(). Add a new loop to your main program, such that it uses the new method on each cat and prints only the stray cats.
- Example of what your output should look like:
Complete List: Minou :==> stray, vaccinated, 3 yrs old Max :==> Burmese, not vaccinated, 1 yrs old Gizmo :==> Bengal, vaccinated, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, 4 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, 4 yrs old Stray cats: Minou :==> stray, vaccinated, 3 yrs old
- Add another loop to your main function, once more, and make it output the Non-vaccinated cats 2 or older.
- Example of what your output should look like:
Complete List: Minou :==> stray, vaccinated, tattooed, 3 yrs old Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Stray cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Non-vaccinated cats 2 or older: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old
Challenge #1: Tattooed Cats |
- Assume that we now want to keep track of whether cats are tattooed or not. A tattoo is a good way to mark cats so that they can be easily identified if lost.
- Add a new boolean field to the class for the tattooed status. True will mean tattooed, False, not tattooed.
- Modify the constructor so that we can pass the tattooed status along with all the other information
- Add a method to Cat, called isTattooed(), that will allow us to test if a cat is tattooed or not.
- Modify your main program so that the tattoo status is included when each cat object is created. You may want to use this new list of cats:
Minou, 3, vaccinated, tattooed, stray Max, 1, not vaccinated, tattooed, Burmese Gizmo, 2, vaccinated, tattooed, Bengal Garfield, 4, not vaccinated, not tattooed, Orange Tabby
- Modify the __str__() method so that it includes the tattoo information in the returned string.
- Example of what __str__() will print:
Minou :==> stray, vaccinated, tattooed, 3 yrs old
- Run your main program again. It should output the same information as before, but this time the tattoo information will also appear when a cat is listed.
- Add a new Non-tattooed cat loop to your main program that will output all the cats that are not tattooed.
- Example of output:
Complete List: Minou :==> stray, vaccinated, tattooed, 3 yrs old Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Stray cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Non-vaccinated cats 2 or older: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-tattooed cats: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old
Challenge #2: Vaccinated and Tattooed Cats |
- Make the main program display all the cats that are vaccinated and tattooed.
- Example of output:
omplete List: Minou :==> stray, vaccinated, tattooed, 3 yrs old Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Stray cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Non-vaccinated cats 2 or older: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-tattooed cats: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Vaccinated and tattooed cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old
Challenge #3: Reading the Cat information from a CSV file |
- Create the short program below and name it createCatCSV.py.
# createCatCSV.py # D. Thiebaut # save several cat definitions into a CSV file. def createCatCSV( fileName ): file = open( fileName, "w" ) file.write( """Minou, 3, vaccinated, tattooed, stray Max, 1, not vaccinated, tattooed, Burmese Gizmo, 2, vaccinated, tattooed, Bengal Garfield, 4, not vaccinated, not tattooed, Orange Tabby Silky, 3, vaccinated, tattooed, Siamese Winston, 1, not vaccinated, not tattooed, stray\n""" ) file.close() def main(): createCatCSV( "cats.csv" ) main()
- Run the program once. Verify that it will have created a new file in the same folder/directory where your program resides. Verify (using Notepad or TextEdit) that this file contains a collection of lines, each representing a cat.
- Now, play with the program below:
# Lab9CatsCSV.py # D. Thiebaut # Seed for a program that reads cat data from # a CSV file. def main(): # set the name of the csv file containing the list of cats fileName = input( "File name? " ) # user enters "cats.csv" # open a csv file file = open( fileName, "r" ) # process each line of the file for line in file: # split the line at the commas words = line.strip().split( ", " ) # skip lines that do not have 5 fields if len( words ) != 5: continue # print the fields for i in range( len( words ) ): print( "words[",i,"]=", words[i].strip(), end=", " ) print() main()
- It reads a file containing several lines where information is separated by commas, and breaks each line into words.
- It is all you need to make your "cat" program read the cat information from a file, rather than from the same old string.
- Merge this program (by putting it into a function, for example), with the one you wrote for Challenge #2, and make your program read the cats from a CSV file.
- This means that your program must
- extract each cat from a line of the file,
- transform the string "vaccinated" in True, and "not vaccinated" in False (it's simpler than you think!)
- transform the string "tattooed" in True, and "not tattooed" in False (same comment),
- transform the string containing the age into an int,
- and store all this information into a Cat object. All the cats should be added to a list.
- Verify that your program outputs the correct lists of cats (vaccinated, 2 and older, vaccinated and tattooed, etc.)
- Example of output:
Complete List: Minou :==> stray, vaccinated, tattooed, 3 yrs old Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Silky :==> Siamese, vaccinated, tattooed, 3 yrs old Winston :==> stray, not vaccinated, not tattooed, 1 yrs old Non-vaccinated cats: Max :==> Burmese, not vaccinated, tattooed, 1 yrs old Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Winston :==> stray, not vaccinated, not tattooed, 1 yrs old Stray cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Winston :==> stray, not vaccinated, not tattooed, 1 yrs old Non-vaccinated cats 2 or older: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Non-tattooed cats: Garfield :==> Orange Tabby, not vaccinated, not tattooed, 4 yrs old Winston :==> stray, not vaccinated, not tattooed, 1 yrs old Vaccinated and tattooed cats: Minou :==> stray, vaccinated, tattooed, 3 yrs old Gizmo :==> Bengal, vaccinated, tattooed, 2 yrs old Silky :==> Siamese, vaccinated, tattooed, 3 yrs old
Moodle Submission
Take the final program you wrote for Part 2 of this lab, and make it get the name of a file from the user (who will enter cats.csv at the prompt), and output only the cats that are not vaccinated, and 2 years or older.
Your program should not output any other information, otherwise the Moodle test program will assume your output is incorrect.
Your program should do its work by using a list of Cat objects instantiated from a class called Cat.
Example
- If the file cats2.csv contains the following information:
Max, 1, vaccinated, not tattooed, stray Black, 3, not vaccinated, tattooed, stray Gizmo, 2, vaccinated, not tattooed, Bengal Winston, 2, vaccinated, tattooed, Bengal Garfield, 3, vaccinated, not tattooed, Burmese Bob, 4, not vaccinated, tattooed, Orange Tabby Minou, 1, vaccinated, tattooed, stray Silky, 3, not vaccinated, tattooed, Siamese
- Then your program should behave as follows:
File name? cats2.csv Black :==> stray, not vaccinated, tattooed, 3 yrs old Bob :==> Orange Tabby, not vaccinated, tattooed, 4 yrs old Silky :==> Siamese, not vaccinated, tattooed, 3 yrs old
<showafterdate after="20180407 12:00" before="20180601 00:00">
Solution Programs
Part 1
# lab9 programs
# D. Thiebaut
# getInput: returns an integer larger
# than 0. Expected to be robust
def getInput():
while True:
x = int( input( "Enter an integer greater than 0: " ) )
if x <= 0:
print( "Invalid entry. Try again!" )
else:
return x
# betterGetInput: returns an integer larger
# than 0. Expected to be robust
def betterGetInput():
# repeat forever...
while True:
# try to get an int
try:
x = int( input( "Enter an integer greater than 0: " ) )
except ValueError:
# the user must have entered something other than an int
print( "Invalid entry. Not an integer. Try again!" )
continue
# There was no errors. See if the number is negative
if x <= 0:
print( "You entered a negative number. Try again!" )
else:
return x
def main1():
num = betterGetInput()
print( "You have entered", num )
# =======================================================================
def example1():
print( "You will need to enter 3 pairs of ints..." )
while True:
try:
x = int( input( "enter a number: " ) )
y = int( input( "enter another number: " ) )
print( x, '/', y, '=', x/y )
break
except ZeroDivisionError:
print( "Can't divide by 0!" )
except ValueError:
print( "That doesn't look like a number!" )
except:
print( "something unexpected happend!" )
def example2( L ):
print( "\n\nExample 2" )
sum = 0
for i in range( len( L ) ):
try:
sum += L[i]
except TypeError:
continue
print( "sum of items in ", L, "=", sum )
def printUpperFile( fileName ):
try:
file = open( fileName, "r" )
except FileNotFoundError:
print( "***Error*** File", fileName, "not found!" )
return
# if we're here, the file is found and open
for line in file:
print( line.upper() )
file.close()
def createTextFile( fileName ):
file = open( fileName, "w" )
file.write( "Welcome\nto\nCSC111\nIntroduction\nto\nComp.\nSci.\n" )
file.close()
def main2():
createTextFile( "csc111.txt" )
example1()
L = [ 10, 3, 5, 6, 9, 3 ]
example2( L )
#example2( [ 10, 3, 5, 6, "NA", 3 ] )
printUpperFile( "csc111.txt" )
#printUpperFile( "csc1111.txt" )
main2()
Part 2
# cats1.py
# D. Thiebaut
# Program for Week #9
# Define a Cat class, and
# use it to create a collection of
# cats.
class Cat:
"""a class that implements a cat and its
information. Name, breed, vaccinated,
tattooed, and age."""
def __init__( self, na, brd, vacc, ag, tat ):
"""constructor. Builds a cat with all its information"""
self.name = na
self.breed = brd
self.vaccinated = vacc
self.age = ag
self.tattooed = tat
def isTattooed( self ):
"""returns True if cat is tattooed, False otherwise"""
return self.tattooed
def isVaccinated( self ):
"""returns True if cat is vaccinated, False otherwise"""
return self.vaccinated
def getAge( self ):
"""returns cat's age"""
return self.age
def getName( self ):
"""returns name of cat"""
return self.name
def getBreed( self ):
return self.breed
def __str__( self ):
"""default string representation of cat"""
vacc = "vaccinated"
if not self.vaccinated:
vacc = "not vaccinated"
tatt = "tattooed"
if not self.tattooed:
tatt = "not tattooed"
return "{0:20}:==> {1:1}, {2:1}, {3:1}, {4:1} yrs old".format(
self.name, self.breed, vacc, tatt, self.age )
def readCatCSV( fileName ):
""" reads the CSV file and puts all the cats
in a list of Cat objects"""
# get the lines from the CSV file
file = open( fileName, "r" )
lines = file.readlines()
file.close()
# create an empty list of cats
cats = []
# get one line at a time
for line in lines:
# split a line in words
fields = line.split( ", " )
# skip lines that do not have 5 fields
if len( fields ) != 5:
continue
# get 5 fields into 5 different variables
name, age, vac, tat, breed = fields
breed = breed.strip()
# transform "vaccinated" or "not vaccinated" in True or False
if vac.lower().find( "not " )==-1:
vac = True
else:
vac = False
# transform "tattooed" or "not tattooed" in True or False
if tat.lower().find( "not " )==-1:
tat = True
else:
tat = False
# add a new cat to the list
cats.append( Cat( name, breed, vac, int(age), tat ) )
# done with the lines. Return the cat list
return cats
def main():
""" main program. Creates a list of cats and displays
groups sharing the same property.
Minou, 3, vac, stray, tat
Max, 1, not-vac, Burmese, tat
Gizmo, 2, vac, Bengal, tat
Garfield, 4, not-vac, Orange Tabby
"""
cats = readCatCSV( input( "File name? " ) )
"""
cat = Cat( "Minou", "stray", True, 3, True)
cats.append( cat )
cats.append( Cat( "Max", "Burmese", False, 1, True ) )
cats.append( Cat( "Gizmo", "Bengal", True, 2, True ) )
cats.append( Cat( "Garfield", "Orange Tabby", False, 4, False ) )
"""
# print the list of all the cats
print( "\nComplete List:" )
for cat in cats:
print( cat )
print( "\nNon-vaccinated cats:" )
for cat in cats:
if cat.isVaccinated()==False:
print( cat )
print( "\nStray cats:" )
for cat in cats:
if cat.getBreed().lower() == "stray":
print( cat )
print( "\nNon-vaccinated cats 2 or older:" )
for cat in cats:
if cat.isVaccinated()==False and cat.getAge() >= 2:
print( cat )
print( "\nNon-tattooed cats:" )
for cat in cats:
if cat.isTattooed()==False:
print( cat )
print( "\nVaccinated and tattooed cats:" )
for cat in cats:
if cat.isVaccinated() and cat.isTattooed():
print( cat )
def lab9Solution():
"""prompts user for file name, and outputs
cats that are not vaccinated, and 2 years or older"""
cats = readCatCSV( input( "File name? " ) )
print()
for cat in cats:
if cat.isVaccinated()==False and cat.getAge() >= 2:
print( cat )
#main()
lab9Solution()
</showafterdate>