How Does Python Know This?


#1

I have a technical/theoretical question: referring to the code below, specifically using the portion of the function "get_class_average" at the bottom of the program, "student" and "students" were never defined earlier in the program. So, how does python know that what is going to be put into the function are literally the names of the students (lloyd, alice, tyler)? Also, how, if it is able to, is it differentiating between plural and singular? Is this a built in feature working in the background of Codecademy? or is this a feature of Python? Thanks!

P.S. Or are "student" and "students" simply empty place holders for what is to be inputted later when the function is called and I'm just missing some basic understanding of how functions work...?

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!
def average(numbers):
    total = float(sum(numbers))
    avg = (total / len(numbers))
    return avg 

def get_average(student):
    homework = float(average(student["homework"]))
    quizzes = float(average(student["quizzes"]))
    tests = float(average(student["tests"]))
    weighted_average = (homework*0.1)+(quizzes*0.3)+(tests*0.6)
    return weighted_average
    
def get_letter_grade(score):
    if score >= 90:
        print "A"
        return "A"
    elif score >= 80 and score < 90:
        print "B"
        return "B"
    elif score >= 70 and score < 80:
        print "C"
        return "C"
    elif score >= 60 and score < 70:
        print "D"
        return "D"
    else:
        print "F"
        return "F"

def get_class_average(students):
    results = []
    for student in students:
        results.append(get_average(student))
    return (average(results))


#2

They're just regular variables, the names have no significance, you're the one defining them


#3

I understand that but my problem is that I don't seem to have explicitly defined either "student" or "students" as variables anywhere in the program... or I'm missing that part. If I HAVE defined them, could you please point to where in the code I do so? Thank you.


#4

To understand why we use students, you must first understand why we use parameters.

As of defining the function, the program does not know whether students is a number, a string, a list, a dictionary, etc. As far as the program is concerned students could be anything. And the the program could care less. It's just a placeholder for whatever you pass into the function when you actually call it. In other words think of parameters like variables, whenever you call a function, the argument you pass into it becomes the value for students. For instance if you called:

get_class_average([lloyd, alice, tyler])

You would essentially be telling the program to run get_class_average(students) except now, students = [lloyd, alice, tyler]. Until a function is actually called, the parameters you have set are valueless placeholders. Once you call the function and pass in arguments for those parameters, they take on value and purpose. What I mean by this is, if you did the following:

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!
def average(numbers):
    total = sum(numbers)
    total = float(total)
    return total/len(numbers)
    
def get_average(student):
    homework = average(student["homework"])
    quizzes = average(student["quizzes"])
    tests = average(student["tests"])
    return float((homework * 0.1) + (quizzes * 0.3) + (tests * 0.6))

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"

def get_class_average(students):
    results = []
    for student in students:
        results.append(get_average(student))
    return average(results)

get_class_average([lloyd, alice, tyler])

Notice how I defined the function using students as a parameter and then I called the function using a list of all the students as an argument. This is telling the program to run the code within get_class_average(students) but replace all mentions of students with that list. Basically it does this:

results = []
for student in [lloyd, alice, tyler]:
    results.append(get_average(student))
return average(results)

This is why we use students as we do in the function. As for why we use student, well...

Just like with students, as of defining the function, the program does not know whether student is a number, a string, a list, a dictionary, etc. As far as the program is concerned student could be anything. And the the program could care less. It's just a placeholder for whatever you pass into the function when you actually call it. In other words think of parameters like variables, whenever you call a function, the argument you pass into it becomes the value for student. For instance if you called:

get_average(lloyd)

You would essentially be telling the program to run get_average(student) except now, student = lloyd. Until a function is actually called, the parameters you have set are valueless placeholders. Once you call the function and pass in arguments for those parameters, they take on value and purpose. What I mean by this is, if you did the following:

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!
def average(numbers):
    total = sum(numbers)
    total = float(total)
    return total/len(numbers)
    
def get_average(student):
    homework = average(student["homework"])
    quizzes = average(student["quizzes"])
    tests = average(student["tests"])
    return float((homework * 0.1) + (quizzes * 0.3) + (tests * 0.6))

get_average(lloyd)

Notice how I defined the function using student as a parameter and then I called the function using lloyd as an argument. This is telling the program to run the code within get_average(student) but replace all mentions of student with lloyd. Basically it does this:

homework = average(lloyd["homework"])
quizzes = average(lloyd["quizzes"])
tests = average(lloyd["tests"])
return float((homework * 0.1) + (quizzes * 0.3) + (tests * 0.6))

lloyd["homework"] is an identifier for the value of "homework" in the dictionary called lloyd.
lloyd["quizzes"] is an identifier for the value of "quizzes" in the dictionary called lloyd.
lloyd["tests"] is an identifier for the value of "tests" in the dictionary called lloyd.

This is why we use student as we do in the function.


#5

Thanks for the in-depth explanation aquaphoenix17! You've been a great help.


#6

■■■■, im having trouble understaning that deep response, will try it again alter when im rested. Basically i got the same problem because my code was faulty when i defined students as "student" and code worked when i removed that bolded line. In my reasoning it was perfectly sound and fit but apparently im missing something.
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!

def average(numbers):
total = sum(numbers)
total = float(total)
return total / len(numbers)
def get_average(student):
student = [lloyd, alice, tyler]
homework = average(student["homework"])
quizzes = average(student["quizzes"])
tests = average(student["tests"])
grade = (0.1 * average(student["homework"]) + 0.3 * average(student["quizzes"]) + 0.6 * average(student["tests"]))
return grade


#7

Yes, rest is important! Don't overwork your brain.

As for adding that bolded line in, you are basically locking the function to only evaluate that situation where student is [lloyd, alice, tyler].

But there are other situations in which this function can be used....such as maybe just getting average of alice or just two of the three students: [alice, tyler].

student is a placeholder(variable) like @aquaphoenix17 said. It's similar to a function in math: f(x) = x + 1 where x is your variable. It can be any number like x=2 or x=3.

But what you are doing is basically, f(x) = 3 + 1. So if I make x into any other number other than 3 (like 4), your f(x) will ALWAYS give out 4 which is incorrect: f(4) = 3 + 1 instead of f(4) = 4 + 1. It is because you are ignoring the input and replacing it with another one.


#8

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