Goals

Upon successful completion of this lab, you should be able to understand and write programs that define and use simple Python classes.


Setup and Practice

Setup

  1. If your lab machine was not started in MacOS when you went to use it, reboot it to MacOS.
  2. Follow these procedures to mount your blue home-directory on the local machine and create a PyCharm project (call it Lab12). You will use PyCharm in the next part, but, it is important that you set up your project now so that if you run into any issue, we can resolve them quickly.
  3. Right-click or control-click to download these 2 files and place them into the directory for this lab:

Part A: Classes and objects

In this part of the lab, you will explore and then modify a new class, the Rectangle class.

Instructions

  1. Enter the following code into the online Python 3 tutor:

    class Rectangle:
        def __init__(self, L, W):
            self.set_length(L)
            self.set_width(W)
    
        def set_width(self, W):
            self.width = W
    
        def set_length(self, L):
            self.length = L
    
        def get_width(self):
            return self.width
    
        def get_length(self):
            return self.length
    
        def get_area(self):
            return self.get_length() * self.get_width()
    
    # STOP HERE
    # This code uses the Rectangle class
    r1 = Rectangle(1, 2) # Statement 1
    r2 = Rectangle(5, 6) # Statement 2
    a1 = r1.get_area() # Statement 3
    a2 = r2.get_area() # Statement 4
    
  2. Step through the code, stopping at the labeled comment (when the red arrow gets to line 23). Notice how the code above the comment sets up the definition of the Rectangle class and its methods. Answer Question 1 in your writeup.
  3. Step through the complete execution of Statement 1, stopping when the red arrow gets to line 24. Notice that the stacks on the right-hand side of the screen grow downward, so that the current function call and the newly created objects are always at the bottom.
  4. Answer Question 2 in your writeup.
  5. Step through the complete execution of Statement 2, and answer Question 3 in your writeup.
  6. Step through the complete execution of Statements 3 and 4, and answer Question 4 in your writeup
  7. Modify the definition of the Rectangle class to add a get_perimeter method. This method should return the perimeter of the rectangle. Then add a statement to the end of the program to test your new method.
  8. Demo. Demo your new method to an instructor. As part of the demo, you will be asked to step through the entire program and answer questions about how it works.
  9. Continue to Part B.

Part B: Define Student class

In this part of lab, you will explore and modify a new class, the Student class.

Instructions

  1. Create and open a new Python source code file named lab12b.py:

    """
    Program: Lab 12
    Author: Your name
    Description: This program will eventually read in a list of students
        and grades from a text file, calculate the students' averages, and 
        print the list of students.
    """
    
    
    class Student:
        '''A class that holds the data for an individual student.'''
    
        def __init__(self, name, scores):
            '''Inits the Student class.
            
            Args:
                name (str): The name of the student.
                scores (list): The scores for the student.
            '''
            self.name = ''
            self.scores = []
    
        def get_average(self):
            '''Returns the average grade.'''
            pass
    
        def print(self):
            '''Prints the student info in the following format:
                name (12 characters), grades (separated by tabs),
                average (formatted to 5 decimal places).
            '''
            # Right now, just prints the student name padded out to 12 characters
            string_to_print = self.name.ljust(12)
            print(string_to_print)
    
    
    def main():
        '''A simple program to test our Student class.'''
        # Try to create and print a student with grades of 8, 9, and 10
        test_student = Student('Test', [8, 9, 10])
        test_student.print()
    
    
    main()
    
  2. Read over the program and run it in the the online Python 3 tutor. Pay attention to how the test_student variable is stored. Then answer Question 5 in your writeup.
  3. Right now, __init__ is initializing the self.name instance variable to the empty string. That means that when we call the print method, we will print an empty string.

    Modify init so that it sets self.name to the name that was passed to it. When you rerun or re-visualize your program, you should see the following output:

    Test
    
  4. Now that the student's name is being printed correctly, let's try to print the student's scores. Add the following lines to the print method, just before the print(string_to_print):

    # Convert list of integers to strings for printing purposes
    # There are shorter ways to do this, but this is the clearest.
    for score in self.scores:
        string_to_print += '\t' + str(score)
    
    This will add the list of scores to the string. The scores will be separated by tabs.
  5. Run your program again. You should still only see

    Test
    
    Answer Question 6 in your writeup.
  6. In the __init__ function, modify the line that initializes self.scores so that self.scores uses the value that was passed to it. Rerun your program. Now you should see:

    Test        	8	9	10
    
  7. Finally, you should print the average. Add the following line to the print method, just before the print(string_to_print):

    string_to_print += '\t' + str(self.get_average())
    

    When you run your program, you should see:

    Test        	8	9	10	None
    
  8. You need to actually define the method get_average for your program to print a value other than None. This method should do the following:
    • If self.scores is empty, return None (instead of, say, crashing).
    • Otherwise, return the average of the values in self.scores, rounded to 5 decimal places.
    It's OK if this function crashes when the list contains non-numeric scores.
  9. Now, when you run your program, you should see the output below:

    Test        	8	9	10	9.0
    
  10. Experiment with the contents of main to be sure that your program works for different student names and scores.
  11. Save this code (lab12b.py). We may refer back to it in Lab 13.
  12. Continue to Part C.

Part C: Write client code for Student

In this part, we will write code that makes use of the Student class. We call this client code because it is using the class, like a customer or a client of the class.

Instructions

  1. Make a new copy of your lab12b.py file, and name it lab12c.py.
  2. Replace your current version of main with the following:

    def main():
        studentlines = readfile("students.txt")
    
  3. Implement the function called readfile that reads the lines of the specified file into a list (one element per line). Feel free to borrow this code from previous labs.

    Note: make this a normal function, not a method of the Student class!

  4. The list studentlines now has each line of the file as a single string. For example, studentlines[0] will be the string

    Linus   25      12      21		30		29
    
    However, we need to separate that into a name and a list of integer scores.
  5. Add the following lines of code to the end of main. The next steps will go into more detail about each item.
    # Loop over the list of lines from the file and
    #   break each line down into a name and scores
    for line in studentlines:
        # TODO 1.
        # Split line into a list. If list is empty, break out of the loop.
    
        # TODO 2.
        # The first item in the list is the student's name
    
        # TODO 3.
        # Convert the remaining items in the list into integers
    
        # TODO 4.
        # Create a new Student variable with that name and scores
    
        # TODO 5.
        # Call the Student print method to print that student's information
    
  6. For TODO 1, split line into a list of strings. Save that list as a variable. Break out of the loop if the list is empty (you can use the keyword break on a line by itself to do this).
  7. For TODO 2, save the first item in your list into a new variable called name.
  8. For TODO 3, create a new list for the scores. Then, convert the remaining items into integers and append them to the new list. You may assume that they will be valid integers.
  9. For TODO 4, create a new Student variable with that name and those scores. Hint: review Part B of the lab if you need a reminder of how to do this.
  10. Finally, for TODO 5, call the print method to print that student's information. Hint: review Part B of the lab if you need a reminder of how to do this.
  11. When you run your code, you should see all of the students from the students.txt file, their scores, and their averages:

    Linus       	25	12	21	30	29	23.4
    Charlie     	12	13	4	9.66667
    Lucy        	30	29	30	29.66667
    Patty       	13	14	15	12	13.5
    Schroeder   	28	21	24.5
    Snoopy      	21	21	21	21.0
    Pigpen      	15	15.0
    Marcie      	30	28	30	29.33333
    Frieda      	15	23	16	18.0
    Spike       	10	8	10	9.33333
    Pooh        	8	9	10	9.0
    Piglet      	24	23	28	25.0
    Christopher 	28	29	30	29.0
    Owl         	30	30	30	30.0
    Rabbit      	29	29	29	29.0
    Eeyore      	12	12	12	12.0
    Kanga       	30	29	30	29.66667
    Roo         	2	1	3	2.0
    Tigger      	0	0	0	0	0	30	5.0
    Heffalump   	21	22	23	22.0
    
  12. Add code to your main function to compute and print the overall average of all the students (that is, the average of all of their averages), rounded to 5 decimal places.

    You should re-use the get_average method to get each student's average, rather than recomputing it inside main. Your final output should look like this:

    Linus       	25	12	21	30	29	23.4
    Charlie     	12	13	4	9.66667
    Lucy        	30	29	30	29.66667
    Patty       	13	14	15	12	13.5
    Schroeder   	28	21	24.5
    Snoopy      	21	21	21	21.0
    Pigpen      	15	15.0
    Marcie      	30	28	30	29.33333
    Frieda      	15	23	16	18.0
    Spike       	10	8	10	9.33333
    Pooh        	8	9	10	9.0
    Piglet      	24	23	28	25.0
    Christopher 	28	29	30	29.0
    Owl         	30	30	30	30.0
    Rabbit      	29	29	29	29.0
    Eeyore      	12	12	12	12.0
    Kanga       	30	29	30	29.66667
    Roo         	2	1	3	2.0
    Tigger      	0	0	0	0	0	30	5.0
    Heffalump   	21	22	23	22.0
    
    Overall average: 19.30333
    
  13. Demo. Call an instructor over to demo your code.
  14. Continue to the next part to submit your program.

Assignment Submission

Instructions

  1. Answer the last question (#7) in your Moodle writeup. Review your answers, and then click the "Next" button at the bottom of the quiz. Once you do that, you should see a "Summary of Attempt" screen.
  2. Click the "Submit all and finish" button. Warning: You must hit "Submit all and finish" so that your writeup can be graded! It is not submitted until you do this. Once you have submitted your quiz, you should see something similar to this at the top of your Moodle window. The important part is that the State shows up as Finished.
    Quiz confirmation
    Please leave this tab open in your browser.
  3. Click on the "Lab 12 code" link in Moodle and open in a new tab. Follow the instructions to upload your source code (lab12c.py) for Lab12. You could either browse for your code or, using a finder window, drag and drop your lab12c.py from your cs115/Lab12 folder to Moodle. You should subsequently see a dialog box which indicates 'Submission Status' as 'Submitted for grading'. Leave this tab open in your browser.
  4. With these confirmation pages open in your browser, you may call an instructor over to verify that you have completed every part of the lab. Otherwise, you are done!