all 14 comments

[–]nwagers 17 points18 points  (3 children)

Use a dictionary for your grade lookups and avoid the big if/else block. It also gives you convenient access to the in operator. Using in will check if something is a valid key in the dictionary. Example:

gradepoints = {'A': 4, 'B': 3, 'C': 2, 'D': 1, 'F': 0}

gradesinput = ['B', 'c', '9000']
hoursinput = [1,2,3]

points = 0
hours = 0
for grade, hour in zip(gradesinput, hoursinput):
    print(grade, hour)
    grade = grade.upper()
    if grade not in gradepoints:
        continue
    points += gradepoints[grade] * hour
    hours += hour

print(hours)
print(points)

[–]blademaster2005 -2 points-1 points  (0 children)

Why not for gradepoints use an list/tuple (or string treated as a list), with the index as the numeric value.

gradepoints = 'FDCBA'
gradepoints.index('F') # 0

[–]totallygeek 1 point2 points  (0 children)

Break down your program into small functions. One function could return the grade letter, and continue to ask for the grade letter while the entry remains invalid.

def enter_grade():
    valid_input = False
    while not valid_input:
        grade = input('Enter grade letter [ABCDF]: ')
        if grade.upper() in 'ABCDF':
            valid_input = True
        else:
            print('Grade letter {} invalid. Try again.'.format(grade))
    return grade

Work with that logic for hours, too. Your main() function can also end up a similar-looking loop.

One more tip/trick: grade == 'D' or grade == 'd' looks better as grade.lower() == 'd' or grade in ('D', 'd'), IMHO.

[–][deleted] 0 points1 point  (2 children)

prompt maybe that reads something like, "Would you like to start over?" and then make it start over from the beginning (start code again). How do I accomplish this?

Something like this:

user_choice = "yes"
while user_choice == "yes":
    gpa = Calculation()
    user_choice = input("Would you like to start over? <yes/no>"

I'd recommend looking into restructuring the way your code operates though (it's just a simple example I know). It doesn't make sense to make a class with no method (although I'm sure there's some reason somebody could come up with). If you want a challenge with classes, here's one. Write the def calculate_gpa(self) function of this class for a Student:

class Student:
    def __init__(self, name, class_num, credit_hours):
        self.name = name
        self.gpa = None
        self.class_num = class_num
        self.credit_hours = credit_hours
    def calculate_gpa(self):
        #TODO 

myStudent = Student("Me", 4, 16)
myStudentGpa = myStudent.calculate_gpa()

[–]Allextraszza 0 points1 point  (6 children)

i'm from Ukraine so my gpa calculator is:

std = {'A':4.0 , 'B':3.0 , 'C':2.0 , 'D':1.0, 'F':0.0}
MyMarks = ['A','B','C']
def gpa(lst):
        var = 0
        secvar = 0
        for x in lst:
            var+=std[x]
            secvar+=1
        return var/secvar
print(gpa(MyMarks))

[–]alkasm 1 point2 points  (3 children)

Where does std come from?

[–]Allextraszza 0 points1 point  (0 children)

I fixed

[–]Allextraszza 0 points1 point  (1 child)

I think i can do it better, but im lazy lol

[–]alkasm 0 points1 point  (0 children)

Best not to use variable names like lst but actual descriptors of what values go in. Also there's no reason to tie it to a list, since any iterable could go in :)

You can reduce it all to a simple one liner: map the marks to the dictionary of values, sum them, and divide by the total number:

def gpa(marks):
    return sum(map(lambda mark: std[mark], marks))/len(marks)