pythonlistabstraction

Why is my Python list not passing through to another function that's dependent on the list even though it did in a less abstracted method?


TRACE LOGS:

Traceback (most recent call last):
File ".../GradeCalculatorPlus/run.py", line 127, in <module>
calculate_grade_final(summatives, formatives, course)
File ".../GradeCalculatorPlus/run.py", line 60, in calculate_grade_final
lowest_grade_possible = lowest_grade(desired_end_grade, summatives, formatives)
File ".../GradeCalculatorPlus/run.py", line 38, in lowest_grade
if average(summatives_copy.append(next_summative_grade), formatives_copy) >= desiredGrade:
File ".../GradeCalculatorPlus/run.py", line 26, in average
int_summatives = [int(numeric_string) for numeric_string in summatives]
TypeError: 'NoneType' object is not iterable

I know that one of the lists is not passing through properly to lowest_grade() but I can't figure out why.

I have heavily abstracted one method call in python. The top most call looks like this (summative and formative are both empty lists that are initialized beforehand)

calculate_grade_final(summatives, formatives, course)

This call goes to the calculate_grade_final() method below

def calculate_grade_final(summatives, formatives, course):
    print('Please enter your FORMATIVE grades:')
    formatives = grade_loop(formatives)
    print('FORMATIVES for ' + str(course) + ':' + str(formatives))
    print('Please enter your SUMMATIVE grades:')
    summatives = grade_loop(summatives)
    print('SUMMATIVES for ' + str(course) + ':' + str(summatives))
    # https://www.wikihow.com/Calculate-Weighted-Average
    average_grade = average(summatives, formatives)
    print('Average for ' + str(course) + ':' + str(average_grade))
    desired_end_grade = input('What is your desired end grade for ' + str(course) + '? ')
    lowest_grade_possible = lowest_grade(desired_end_grade, summatives, formatives)
    print('The lowest possible grade you can get to get a ' + str(desired_end_grade) + ' for ' + str(
        course) + ' is either a SUMMATIVE grade of ' + str(
        lowest_grade_possible[0]) + ' OR a FORMATIVE grade of ' + str(lowest_grade_possible[1]))

The issue then goes to the lowest_grade() method which looks like this:

def lowest_grade(desiredGrade, summatives, formatives):
    possibilities = []
    summatives_copy = summatives
    formatives_copy = formatives
    for next_summative_grade in range(101):
        if average(summatives_copy.append(next_summative_grade), formatives_copy) >= desiredGrade:
            possibilities.append(next_summative_grade)
            break
    for next_formative_grade in range(101):
        if average(summatives_copy, formatives_copy.append(next_formative_grade)) >= desiredGrade:
            possibilities.append(next_formative_grade)
            break
    return possibilities

Which then goes to the average() method which looks like this:

def average(summatives, formatives):
    # summatives and formatives are stored in a list of strings so I quickly convert it into a list of integers
    # basically the array is like ['97','56','44'] and I convert it into [97,56,44]
    int_summatives = [int(numeric_string) for numeric_string in summatives]
    int_formatives = [int(numeric_string) for numeric_string in formatives]
    return (mean(int_summatives) * summative_weighting_factor) + (
                mean(int_formatives) * formative_weighting_factor)

However the average() method is throwing a NoneType error based on the Python traceback despite the fact that I called it earlier in calculate_grade_final() which resulted in the course grade average of 92

TERMINAL INPUTS:

Please enter your FORMATIVE grades:
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)98
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)100
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)100
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)100
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)98
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)97
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)100
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)100
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)stop
FORMATIVES for AP American Lit Lang/Comp:['98', '100', '100', '100', '98', '97', '100', '100']
Please enter your SUMMATIVE grades:
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)93
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)85
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)92
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)95
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)88
Enter a number grade (no fractions or percentages!) (Type 'stop' to stop the loop)stop
SUMMATIVES for AP American Lit Lang/Comp:['93', '85', '92', '95', '88']
Average for AP American Lit Lang/Comp:92.73124999999999
What is your desired end grade for AP American Lit Lang/Comp? 95

(the last input (95) is what breaks the program and causes the average() method to somehow not get the summative and formative lists despite average() working for the Average for AP American Lit Lang/Comp:92.73124999999999 line of input)

I tried adding a copy of the summative and formative lists to lowest_grade() because I thought it would fix the problem of the lists not passing through to the final average() method but that didn't work either.


Solution

  • in lowest_grade function, make seperate step for append and then pass the list to average and do check there

    change here, dont do append in the average function. do that in the previous step and pass the updated list to function to do checking

    -> if average(summatives_copy.append(next_summative_grade), formatives_copy) >= desiredGrade:

    ->if average(summatives_copy, formatives_copy.append(next_formative_grade)) >= desiredGrade: