Error only produced in code academy: Oops, try again. get_average(alice) raised the following error: string indices must be integers, not str


#1



https://www.codecademy.com/courses/python-beginner-en-qzsCL/1/2?curriculum_id=4f89dab3d788890003000096


The code runs fine locally on my computer, I would like to know what the meaning of the error is ? the result is:

Lloyd
80.55
Alice
91.15
Tyler
79.9


No errors


lloyd = {
   "name": "Lloyd",
   "homework": [90.0, 97.0, 75.0, 92.0],
   "quizzes": [88.0, 40.0, 94.0],
   "tests": [75.0, 90.0]
}
alice = {
   "name": "Alice",
   "homework": [100.0, 92.0, 98.0, 100.0],
   "quizzes": [82.0, 83.0, 91.0],
   "tests": [89.0, 97.0]
}
tyler = {
   "name": "Tyler",
   "homework": [0.0, 87.0, 75.0, 22.0],
   "quizzes": [0.0, 75.0, 78.0],
   "tests": [100.0, 100.0]
}

# Add your function below!
students = [lloyd,alice,tyler]
def get_average(students):


    for student in students:
        total = 0
        total_quizz = 0
        total_grades = 0
        sum = 0
        #calculating homework avg
        for grades in student["homework"]:
            sum = 0
            length = len(student["homework"])
            total = total + grades
            float(total)
            homeworks = ((total/float(length)) * 0.1)


        for marks in student["quizzes"]:
            haykel = len(student["quizzes"])
            total_quizz += marks
            quizz = ((total_quizz/float(haykel)) * 0.3)

        for grades in student["tests"]:
            length = len(student["tests"])
            total_grades += grades
            tests = (total_grades/float(length)) * 0.6

        print student["name"]
        sum = quizz + homeworks + tests
        print sum

get_average(students)


#2

Whoa, that is a lot to take in. My first question is, why would we want everyone's average everytime we call the get_average function? Wouln't we want this to be simple utility that takes a dictionary and computes a weighted average for just that one student?

Since your code has veered off the instruction path somewhat, then let's take license to stay afield...

Say we have an dictionary that describes all the weights for a grading system:

>>> weights = {
    'homework': 0.1,
    'quizzes': 0.3,
    'tests': 0.6
}
>>>

Something to note: The above weights will always add up to 1.

Now we set up a function to take only one student dictionary:

>>> def average(grades):
	return float(sum(grades)) / len(grades)

>>> def get_average(student):
    grade = 0
    for weight in weights:
        grade += average(student[weight]) * weights[weight]
    return grade

>>>

Now we run it...

>>> get_average(lloyd)
80.55
>>>

It makes perfect sense to have this function work for one student at a time.


#3

Hi,
This is the code I've done. It shows the same error - Oops, try again. get_class_average([alice]) resulted in an error: list indices must be integers, not str. Please help. I dont know where i've gone wrong. Should i make a student list? and is there a way to pre define the list components as string or int?
lloyd = {
"name": "Lloyd",
"homework": [90.0, 97.0, 75.0, 92.0],
"quizzes": [88.0, 40.0, 94.0],
"tests": [75.0, 90.0]
}
alice = {
"name": "Alice",
"homework": [100.0, 92.0, 98.0, 100.0],
"quizzes": [82.0, 83.0, 91.0],
"tests": [89.0, 97.0]
}
tyler = {
"name": "Tyler",
"homework": [0.0, 87.0, 75.0, 22.0],
"quizzes": [0.0, 75.0, 78.0],
"tests": [100.0, 100.0]
}
def average(numbers):
total = sum(numbers)
total = float(total)
x=total/len(numbers)
return x

Add your function below!

def get_average(student):
homework= average(student["homework"])
quizzes= average(student["quizzes"])
tests = average(student["tests"])
return 0.1*homework + 0.3*quizzes + 0.6*tests

def get_letter_grade(score):
if score >= 90 :
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else :
return "F"
get_letter_grade(get_average(lloyd))

def get_class_average(students):
results=[]
x= get_average(student)
results.append(x)
average(results)


#4

In that function you are handing in a list of student identifiers, each referencing a dictionary. When expected to report on all students, such as a class average, then we have to iterate though that list of identifiers to accumulate a resulting list of grades, that we average in the return.

That means a loop.


#5

Hi,
So i need to make a loop in the get_letter_grade function? didnt really understand.
Also, Should i make a student list? and is there a way to pre define the list components as string or int?


#6

A function should not affect the environment it exists in. Something in, something out. While we can get away with a lot of things using global objects, it's the one thing we work hard to stay away from. The only thing that should exist globally is data (and in the browser, event listeners).

In this exercise we have global data objects, and a list that identifies them. Not ideal, but for our purposes, ideal. It demonstrates that the objects are not stored in the list, only their identifiers (references). students is merely a reference list.

How do our functions interact with the global data objects? By reference only? That is good design. Yes, we do need to loop through a list when given one, and yes we should expect one. Later on down the road you will learn how to validate inputs to make sure they conform to the type and dimensions assumed by the running code.

Writing utilities means narrowing down the expectations of individual functions. We don't write a program in a function; we write for utility. This lends itself to pure functional programming. It may not be obvious, but these past few lessons have been leaning toward that concept.


#7

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.