Search code examples
pythonfunctionzero

GPA Calculator (division by zero) - Python


This is my code for a simple GPA calculator. I am getting an error (see report) even though there is one course in the list as I follow the input and enter in the course. Maybe it has something to do with the placement of the call to the displayOutputTable function?

class Course(object):
    def __init__(self, courseName, letterGrade):
        self.courseName = courseName
        self.letterGrade = letterGrade


courseList = []

def acceptInput():
   courseList = []
   choice = input("Type ‘a’ to add new class or ‘e’ to end. ")
   if choice == 'a':
       courseName = input("Class Name? ")
       letterGrade = input("Grade? ")
   course = Course(courseName, letterGrade)
   courseList = courseList + [course]   
   print(courseList)
    # Create Course object using local data from user 
    # Add this new course object to courseList list 

def convertGradeToPoints(letterGrade):
  creditValue = 0  
  for i in courseList:
        if letterGrade == "A":
           creditValue = 4.0
        if letterGrade == "B":
           creditValue = 3.0
        if letterGrade == "C":
           creditValue = 2.0
        if letterGrade == "D":
           creditValue = 1.0
        if letterGrade == "F":
           creditValue = 0.0


        return creditValue

def calculateGPA():
    numbercourseList = len(courseList)
    totalpoints = 0
    for course in courseList:
        totalpoints  =  totalpoints + convertGradeToPoints(course.letterGrade)
    return totalpoints/numbercourseList

def displayOutputTable():
    print ("COURSE NAME \t LETTER GRADE \t POINTS")
    print("-------------------------")
    for course in courseList:
        print(course.courseName + "\t" + course.letterGrade + "\t" + convertGradeToPoints(course.letterGrade))   


    print("Total unweighted gpa" + "\t" + str(calculateGPA()))

acceptInput()
displayOutputTable()

here is the error report:

Traceback (most recent call last):
  File "C:/Users/Fred/Desktop/tester.py", line 56, in <module>
    displayOutputTable()
  File "C:/Users/Fred/Desktop/tester.py", line 53, in displayOutputTable
    print("Total unweighted gpa" + "\t" + str(calculateGPA()))
  File "C:/Users/Fred/Desktop/tester.py", line 44, in calculateGPA
    return totalpoints/numbercourseList
ZeroDivisionError: int division or modulo by zero

Solution

  • course[] is a global variable. You can only reassign a global variable in a local scope by first declaring it global to bind the global name to the local scope. Otherwise, when you do courseList = [], what's actually happening is a new variable named courseList is assigned a list in the local scope.

    def acceptInput():
       global courseList
       courseList = []
       choice = input("Type ‘a’ to add new class or ‘e’ to end. ")
       if choice == 'a':
           courseName = input("Class Name? ")
           letterGrade = input("Grade? ")
       course = Course(courseName, letterGrade)
       courseList = courseList + [course]   
       print(courseList)
        # Create Course object using local data from user 
        # Add this new course object to courseList list 
    

    Alternatively, the way to do it by only mutating the LIST object without REASSIGNING it.

    def acceptInput():
           courseList.clear()
           choice = input("Type ‘a’ to add new class or ‘e’ to end. ")
           if choice == 'a':
               courseName = input("Class Name? ")
               letterGrade = input("Grade? ")
           course = Course(courseName, letterGrade)
           courseList.append(course)   
           print(courseList)
            # Create Course object using local data from user 
            # Add this new course object to courseList list 
    

    Also, not sure why you want to clear your list of courses every time you accept input of a new course. You'll only ever have one course this way.

    Edited for your comment:

    How do I make it so the console keeps asking me for input after I submit one class

    The answer to this is to use a looping construct, which is a fundamental basic construct of every imperative programming language out there. Perhaps you'd do well to consider learning from a basic python tutorial such as LearnPythonTheHardWay if you do not know this.

    I'll also include a sigterm/sigint handler to handle ctrl+c without exception.

    import signal
    stop = False
    def exit():
        global stop
        stop = True
    signal.signal(signal.SIGINT, lambda signum, frame: exit())
    signal.signal(signal.SIGTERM, lambda signum, frame: exit())
    while not stop:
        acceptInput()
        displayOutputTable()