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 trialCarlos Marin
8,009 PointsKeyError?
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.
# 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
8,009 PointsMy 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
8,009 PointsUpdate: 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
8,009 PointsLASTEST 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
8,009 PointsUPDATE:
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
Python Development Techdegree Student 36,887 PointsHi 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
8,009 PointsThank 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
Carlos Marin
8,009 PointsCarlos Marin
8,009 PointsUPDATE: 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?