CS303E Homework 7

Instructor: Dr. Bill Young
Due Date: Wednesday, March 6, 2024 at 11:59pm

Assignment

In this assignment, you will define a simple Student class. Each Student object contains a name (string), and two exam grades (floats or integers). You will always supply a name when you create the class, and also may supply one or both of the exam grades. If you don't supply an exam grade, it should default to None (indicating that that grade is not yet been recorded). Remember that None is a Python constant; it's not the string "None".

You do not need to validate the exam scores entered by the user; you can assume that they are numbers (integer or float), though the numbers can be arbitrary and can even be negative. You should also be able to return the student's average, assuming both exam scores are available. Define a __str__ method so that you can print the Student information in a nice format. See the sample output below.

Your code must appropriately handle the case where an exam grade is recorded as None. That is, it shouldn't crash if you ask for that grade or the average. See the example usage below.

You must have the Student class. It must have setters and getters for each of the two exam grades, and a getter for the name. You don't need a setter for the name field; we'll assume names don't change. Name your methods as illustrated by the example below. You can have additional subsidiary functions if you find them useful either within the class or outside it, but you don't have to.

Make the class data private. That is, the name and exam grades should not be accessible outside the class directly, but only through the setters and getters.

Sample Output

Please make the behavior of your class conform to these examples. Note that these examples use the Python interactive loop. You can also call your class from within another Python program.
> python
Python 3.6.9 (default, Jan 26 2021, 15:33:00) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Student import *
>>> susie = Student("Susie Q.")
>>> print( susie )
Student: Susie Q.
  Exam1: None
  Exam2: None
>>> susie.getName()
'Susie Q.'
>>> susie.getExam1Grade()              # Notice that None doesn't print
>>> susie.setExam1Grade( 100 )
>>> print( susie )
Student: Susie Q.
  Exam1: 100
  Exam2: None
>>> susie.getExam1Grade()  
100
>>> susie.getAverage()
Some exam grades not available.
>>> susie.setExam2Grade(87)
>>> print( susie )
Student: Susie Q.
  Exam1: 100
  Exam2: 87
>>> susie.getAverage()
93.5
>>> bob = Student( "Bobbie D.", 47, 92 )
>>> print( bob )
Student: Bobbie D.
  Exam1: 47
  Exam2: 92
>>> bob.getAverage()
69.5
>>> clark = Student( "Clark K.", 100 )
>>> print( clark )
Student: Clark K.
  Exam1: 100
  Exam2: None

Turning in the Assignment

The class should be in a file named Student.py. Submit the file via Canvas before the deadline shown at the top of this page. Submit it to the assignment weekly-hw7 under the assignments sections by uploading your python file.

Your file must compile and run before submission. It must also contain a header with the following format:

# File: Student.py
# Student: 
# UT EID:
# Course Name: CS303E
# 
# Date:
# Description of Program: 

Programming tips

Classes are what make object-oriented (OO) languages like Python object-oriented. In Python every data item is an instance of a class, including numbers and strings. In early OO languages like Smalltalk this was much more explicit. For example, since 1 was an object, if you wanted to add 2 to 1, you had to call the add method on 1, like "1.add(2)". That gets tedious pretty fast!

But, in effect, that's still what's happening in Python. It's just that they hide it under a nicer syntax. For example, when you write "x + y" in Python, that's really a short way of calling: "x.__add__(y)", the __add__ method on the class of x. ("Magic methods" like __add__ and __str__ are explained in Slideset 7.)

>>> i1 = 10
>>> i2 = 20
>>> i1.__add__(i2)
30
>>> i1 + i2
30
Note that you can't call __add__ directly on integer literals; "10.__add__(20)" isn't allowed. BTW, when you define a convenient notation for a more cumbersome underlying syntax, that's often called "syntactic sugar."

Luckily, the syntactic sugar means that you can use the familiar syntax of arithmetic almost all the time when you're doing arithmetic in Python. But Python also allows you to "overload" that familiar syntax in some very unfamiliar contexts. You've already seen that you can add two numbers; you can also "add" (concatenate) two strings. That's just because the __add__ method is defined in the string class to be concatenation. IF you wanted to define a way to "add" two Student records using the syntax "susie + bob" you could do it in Python and give it whatever meaning you wanted simply by defining "__add__" on the class. For example, if you wanted to "add" two Circles together by defining a new Circle that has the sum of their areas, you could do that. You could even re-define the meaning of "+" on integers, but you'd almost certainly regret that!