Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Python Collections (2016, retired 2019) Dictionaries Teacher Stats

Carlos Marin
Carlos Marin
8,009 Points

KeyError?

Create a function named most_courses that takes our good ol' teacher dictionary.

most_courses should return the name of the teacher with the most courses. You might need to hold onto some sort of max count variable.

Pyhon says:

Traceback (most recent call last): File "<stdin>", line 1, in <module> Files"<stdin>", line 7, in most_courses KeyError: 'name'

Can someone please explain to me what the interpreter is doing? All the functions work except the most_courses function.

teachers.py
# The dictionary will look something like:
# {'Andrew Chalkley': ['jQuery Basics', 'Node.js Basics'],
#  'Kenneth Love': ['Python Basics', 'Python Collections']}
#
# Each key will be a Teacher and the value will be a list of courses.
#
# Your code goes below here.
def num_teachers(dictionary):
    return len(dictionary.keys())

def num_courses(dictionary):
    total = 0
    for teacher in dictionary:
        total += len(dictionary.get(teacher))
    return total

def courses(dictionary):
    courses = []
    for teacher in dictionary:
        for course in dictionary.get(teacher): #loop through every course a teacher has
            courses.append(course)
    return courses

def most_courses(dictionary):
    winner = {"name": 0}
    for teacher in dictionary:
        points = 0
        for course in dictionary.get(teacher): #loop through every course a teacher has
            points += 1 #adds 1 for every course
            if points > winner['name']: 
                winner =  {teacher: points}
    return winner.values() # returns dict_values([0]) ;needs to access name of winner
Carlos Marin
Carlos Marin
8,009 Points

UPDATE: converted "return winner.values()" into "return winner[teacher]" and it passed. BUT there is still a problem I copied that code into my Python interpreter and I still get the same Traceback as the one I tagged at the beginning of this question.
What is the explanation for this?

Carlos Marin
Carlos Marin
8,009 Points

My guess is that after I go through my first iteration, the winner dictionary changes, therefore rendering my "if point > winner['name']:" condition useless.

Carlos Marin
Carlos Marin
8,009 Points

Update: After I had posted the question, I refreshed the challenge and it unknowingly took me to the first step. I then submitted my answer and it said "correct!" so I had thought I fixed the issue.

Carlos Marin
Carlos Marin
8,009 Points

LASTEST UPDATE:

def most_courses(dictionary):
    for teacher in dictionary:
        winner = {teacher: 0}
        points = 0
        for course in dictionary.get(teacher): #loop through every course a teacher has
            points += 1 #adds 1 for every course
            if points > winner[teacher]: 
                winner =  {teacher: points}
    return winner[teacher] # returns value of courses not "winner's name"
Carlos Marin
Carlos Marin
8,009 Points

UPDATE:

def most_courses(dictionary):
    for teacher in dictionary:
        winner = {teacher: 0}
        points = 0
        for course in dictionary.get(teacher): #loop through every course a teacher has
            points += 1 #adds 1 for every course
        if points > winner[teacher]: 
            winner =  {teacher: points}
            for name in winner:
                return name
    return winner[teacher]

1 Answer

Alex Koumparos
seal-mask
.a{fill-rule:evenodd;}techdegree
Alex Koumparos
Python Development Techdegree Student 36,887 Points

Hi Carlos,

Let's step through your code line by line, and see if the issues jump out at us:

def most_courses(dictionary):
    for teacher in dictionary:

On our first iteration (and using the provided example values), teacher will be 'Andrew Chalkley'.

        winner = {teacher: 0}

Every time we enter a new iteration of the for loop we create a new dictionary with a single key, in this case 'Andrew Chalkley' and a corresponding value of 0. We then assign that dictionary to the variable winner.

        points = 0

In each iteration of the main for loop we set the initial value of points to 0.

        for course in dictionary.get(teacher): #loop through every course a teacher has
            points += 1 #adds 1 for every course

Now we have an inner for loop where we get the value for the dictionary item with a key of teacher (in this case 'Andrew Chalkley'). This gives us the list ['jQuery Basics', 'Node.js Basics']. We iterate through that list and each time we increment points. This for loop is equivalent to getting the length of the list and assigning that length to points.

if points > winner[teacher]: 

After the inner loop finishes and we have a final value for points, we check if the value of points is greater than the value of winner's single item (in this case key: 'Andrew Chalkley' and value: 0). Note, this will always be true if the teacher has any courses, since you always initialise winner with 0 and don't touch winner again before this if statement.

Since for any teacher with any courses this will be true, the true branch of the if statement will be executed:

            winner =  {teacher: points}
            for name in winner:
                return name

We now replace the old winner dictionary with a new dictionary. This new dictionary is {'Andrew Chalkley': 2}.

We then go into a for loop through winner (which only has one element) and return the only name inside that dictionary.

The outer for loop will never be executed again because we returned from the function the first time we saw a teacher with a non-zero number of courses. So we'll never even consider how many courses Kenneth Love teaches, or any other teacher.

Let's suppose for a moment that we didn't return as soon as we had a teacher with any points. For now, we'll just print the name, so that we can see what happens when we continue the outer loop, but once you come to fix your code, you're going to need to do something else to record the value of your winner-so-far, not just print it to the console.

So, just for demonstration purposes, let's replace return name with print(name).

Our first iteration of the loop will print 'Andrew Chalkley'. We've now got to the end of the first iteration of the loop.

Now we start the second iteration of the loop.

        winner = {teacher: 0}

Just like in the first iteration, we create a new dictionary, this time it has the single key 'Kenneth Love' and value 0. Just as before, we assign that one-element dictionary to a variable, called winner.

Then we move through the loop just as before:

  • we create a new variable called points and give it the value 0;
  • we figure out the length of Kenneth Love's courses list and assign that to points;
  • we check if points is greater than 0, which it is;
  • we iterate through the single-element dictionary winner and get the first (and only) name in the dictionary: 'Kenneth Love';
  • we print 'Kenneth Love' to the console (courtesy of our temporary print statement).

Now the for loop is finished, and so we execute the code outside of the for loop.

return winner[teacher]

Here, teacher is whatever the last value was assigned to it by the for loop (remember we did for teacher in dictionary to iterate through the dictionary). Since 'Kenneth Love' was the value for teacher during the final iteration of the loop, it is still Kenneth Love.

The winner dictionary is whatever we assigned to it last, which you remember was winner = {teacher: points}. Given the example inputs this would be {'Kenneth Love': 2}.

Thus we return the value 2.

The question tells us to return the name of the person who has the most courses. There is no teacher with the name 2.

Let's pretend that you returned the key instead of the value. That's accidentally the right value where the last teacher in the list has the most (or joint-most) courses. But let's suppose that Kenneth had only 1 course, not 2. Since Kenneth is the last person we loop through, and we only keep his values, the final value of the dictionary would be {'Kenneth Love': 1} and you would return 1.

But 'Andrew Chalkley' would be the right answer, since he still has 2 courses.

Hope this review of your code has highlighted some of the issues for you, and given you some hints for how to proceed.

If you're still stuck, let me know and I'll give you some more hints.

Cheers

Alex

Carlos Marin
Carlos Marin
8,009 Points

Thank you Alex! that post was very insightful. I was able to complete my task, and got some experience with tracking down issues; by running segments at a time and making sure they send the correct information along.

def most_courses(dictionary):
    champion = {'points': 0}
    winner_name = ''
    for teacher in dictionary:
        winner = {teacher: 0}
        for course in dictionary.get(teacher): 
            winner[teacher] += 1
        print(winner)
        if winner[teacher] >= champion['points']: 
            champion['points'] = winner[teacher]
            winner_name = teacher
    return winner_name