FAQ: Survey of Computer Science - The Tale of Kenny - Kenny the Teacher

Hey guys,

I’m just starting out and am curious about a few lines I don’t understand. Can someone please explain the following:

top_of_class = list(grades.keys())[0] - This is a list of all grades based on their number?

And (grades[student_a] > grades[top_of_class]): - Top of class isn’t defined yet?

Is the Else if code necessary in this situation?

Hopefully you have covered dictionaries and some of their methods?

student_grades = {"Jeremy" : 87, "Kyla" : 82, "Ayesha" : 90, "Aleida" : 94, "Todd" : 79, "Maxwell" : 98, "Yolonda" : 81, "Kiyoko" : 71, "Dagmar" : 73, "Laura" : 91, "Shimeah" : 81, "Songqiao" : 92, "Frankie" : 87, "Natalia" : 95, "Gonzalo" : 82, "Pavel" : 78}

The keys in the dictionary above are the student names. The above statement extracts a list of the just the names, and sets the temporary variable to the first item in the list. We will be going through that list to pair up the highest and lowest grades while accessing the dict values by key.

It is defined in the line above, as a student name from the list.

Hi there!

Although I do understand most of the code of The Tale of Kenny, something keeps bugging me:

First, a dictionary is made of all the names and the grades, called student_grades.

student_grades = {“Jeremy” : 87, “Kyla” : 82, “Ayesha” : 90, “Aleida” : 94, “Todd” : 79, “Maxwell” : 98, “Yolonda” : 81, “Kiyoko” : 71, “Dagmar” : 73, “Laura” : 91, “Shimeah” : 81, “Songqiao” : 92, “Frankie” : 87, “Natalia” : 95, “Gonzalo” : 82, “Pavel” : 78}

Then a function is defined in order to find the highest grade. But, how does that function ‘know’ it’s supposed to search in the dictionary student_grades, while student_grades is never mentioned or referred to in the function?

def highest_grade(grades):

top_of_class = list(grades.keys())[0]

for student_a in grades:

for student_b in grades:

  if (grades[student_a] > grades[student_b]) and (grades[student_a] > grades[top_of_class]):

    top_of_class = student_a

  elif (grades[student_b] > grades[student_a]) and (grades[student_b] > grades[top_of_class]):

    top_of_class = student_b

return top_of_class

Thanks!

The important part is that the function kennys_algorithm is called in the following way-
kennys_algorithm(student_grades)

Note that student_grades is included as an argument to this function. In Python we’d be passing a reference to our student grades dictionary to this function so the function can now work with the data contained in student_grades. In truth it’s a little more complex than this but that’s unimportant for code foundations.

Perhaps using the parameter name would make more sense to you at this point?
kennys_algorithm(grade_dict=student_grades)
The argument we pass to kennys_algorithm is assigned to the name grade_dict inside the function.

Consider having a brief look at the following FAQ which covers some details on how to format code for the forums (it makes it much easier to read).

Hi tgrtim,

thanks for your reply; I do understand what is actually happening in the code, I just don’t understand how the first function manages to pluck the values out of the dictionary when that dictionary isn’t mentioned anywhere in the function.

I mean, how it that function supposed to ‘know’ where to get its data from?

Apparently, the variable ‘grades’ automatically searches in the dictionary. And how does that work?

Apologies if I used the outermost function as an example but this function is the one that calls the others.

The function highest_grade has one parameter (grades):
def highest_grade(grades)

So when we call this function we use one argument. Whatever argument we pass is effectively assigned to that parameter name inside the function.

For example calling the function with a dictionary called grade_dict like so…
highest_grade(grade_dict)
isn’t much different to simply assigning the same object to a new name (but only within the function)
grades = grade_dict

So now grades is linked to the dictionary inside our function. This is because we passed our dictionary as the argument to that function. It knows about the data because we told it exactly what data it should use.

Perhaps an example would be better-

def multiply_by_three(x):
    # there are no references to my_number within this function
    return x * 3


my_number = 10
print(multiply_by_three(my_number))
Output: --> 30
print(multiply_by_three(1))
Output: --> 3

This behaves a little bit like assigning x the same object as referenced by my_number
x = mynumber
or in the second function call to the integer 1
x = 1
… but only for the duration of that function. The power of functions is that you can re-use them with different arguments to perform complex operations without re-writing the code every time.

Ah, that was the missing link for me, Thanks a bunch!

2 Likes

So in this exercise, why not order the list from high to low, split it in half and match to halves - it seems to be a more straightforward approach than than the one Kenny uses? I am new to coding, so not sure what the code would look like, but it’s probably possible, right? :slight_smile:
Thanks!

1 Like

I think I understand what you mean and yes that sounds like a possible solution :+1:. If you run the codebyte below you’ll see that there is possibly one small step missing regarding the order. In Python this is fairly simple but knowing how to implement this as an algorithm is a useful skill. For this particular problem though, the split (and sort), would probably be easier :slightly_smiling_face:.

# Less students for ease... student_grades = { "Yolonda": 81, "Todd": 79, "Kyla" : 82, "Aleida" : 94, } print( f"Original student grades = \n" f"{student_grades}\n" ) # sort by the score... sorted_grades = sorted( student_grades.items(), # key here sorts by score instead of name key=lambda x: x[1], reverse=True ) print( f"Sorted student grades = \n" f"{sorted_grades}\n" ) # Split list in two halves middle = len(sorted_grades) // 2 # Up to the middle (index) split1 = sorted_grades[:middle] # From the middle onwards split2 = sorted_grades[middle:] print("Link the two halves of the list-") print(f"{split1}") print("\t | \t\t\t |") print(f"{split2}")

We should really be linking the highest score to the lowest score so we need to sort that second half of the list again.

1 Like