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 trialElizabeth McInerney
3,175 PointsPython collections/dictionaries/teacher assignment
When bottom 9 lines of this code runs, it replaces every teacher in the list with the last teacher in the list (along with his number of classes). I don't understand why it does not append.
# The dictionary will be something like:
# {'Jason Seifer': ['Ruby Foundations', 'Ruby on Rails Forms', 'Technology Foundations'],
# 'Kenneth Love': ['Python Basics', 'Python Collections']}
#
# Often, it's a good idea to hold onto a max_count variable.
# Update it when you find a teacher with more classes than
# the current count. Better hold onto the teacher name somewhere
# too!
#
# Your code goes below here.
# The dictionary will be something like:
my_dict = {'Jason Seifer': ['Ruby Foundations', 'Ruby on Rails Forms', 'Technology Foundations'],
'Kenneth Love': ['Python Basics', 'Python Collections']}
#
# Often, it's a good idea to hold onto a max_count variable.
# Update it when you find a teacher with more classes than
# the current count. Better hold onto the teacher name somewhere
# too!
#
# Your code goes below here.
def most_classes(my_dict):
largest = 0
for key in my_dict:
if len(my_dict[key]) > largest:
largest = len(my_dict[key])
busy_teacher = key
print(busy_teacher)
return busy_teacher
most_classes(my_dict)
def num_teachers(my_dict):
number = 0
for key in my_dict:
number += 1
return number
num_teachers(my_dict)
# looking to create a list of lists in the format [<name>,<number of classes>]
my_list = ['name',0]
list_of_lists = []
def stats(my_dict):
for key in my_dict:
my_list[0] = key
my_list[1] = len(my_dict[key])
list_of_lists.append(my_list)
return list_of_lists
stats(my_dict)
4 Answers
William Li
Courses Plus Student 26,868 PointsHi, Elizabeth McInerney you don't need the my_list
variable as a placeholder for the temp values. You could simplify the code this way.
def stats(my_dict):
result = []
for key in my_dict:
result.append([key, len(my_dict[key])])
return result
This would work.
Now, as to why your code isn't working like it supposed to. It's because of these 3 lines.
my_list[0] = key
my_list[1] = len(my_dict[key])
list_of_lists.append(my_list)
Here, it actually brings up a VERY important topic in Python. Pass by Reference VS Pass by Value.
On each iteration of the dictionary key, the 0, and 1st index of my_list
values got reassigned, then my_list
was appended to the list_of_lists
. The final result of the list_of_lists
looks sth like this. [[key1, number1], [key2, number2], [key3, number3] ...].
The key1, key2, key3
, number1, number2, number3
here aren't holding the actual values, they all reference to whatever values key
and len(my_dict[key]
point to.
And since the values of key
and len(my_dict[key]
change each time it iterates through the key in the dictionary, the values that key1, key2, key3
, number1, number2, number3
reference to change accordingly. Therefore when the iteration is over,
it replaces every teacher in the list with the last teacher in the list (along with his number of classes).
Perhaps it'd help you see it better if we look at a simpler examples here.
li = []
a = [1,2,3]
b = a # assign a to b
a[0] = 10 # reassign the 0th index value of a
print(a) # => [10, 2, 3]
print(b) # => [10, 2, 3]
li.append(a)
li.append(b)
print(li) # => [[10,2,3],[10,2,3]]
a[0] = 4
print(li) # => [[4,2,3],[4,2,3]]
The b list changes even though we only modified the a list, that's because both a and b point to the same list, you change one, change the other one.
One last thing, In your original code
# looking to create a list of lists in the format [<name>,<number of classes>]
my_list = ['name',0]
list_of_lists = []
def stats(my_dict):
for key in my_dict:
my_list[0] = key
my_list[1] = len(my_dict[key])
list_of_lists.append(my_list)
return list_of_lists
stats(my_dict)
If you wanna make it works, make one small change in this line list_of_lists.append(my_list)
list_of_lists.append(my_list[:])
By doing so, you're appending a copy of my_list
into list_of_lists instead of just a reference to the list.
To learn more about Pass by Reference VS Pass by Value in Python, you can check out these 2 articles:
- How do I write a function with output parameters (call by reference)?
- Is Python pass-by-reference or pass-by-value?
Hope this helps.
Elizabeth McInerney
3,175 PointsWow, I had no idea. Have we learned that yet?
Elizabeth McInerney
3,175 PointsI see that your change works, but I don't understand why append(my_list) appends something that has pointers that change with each loop through the function, while append(my_list[:]) appends something that is fixed.
The article "Is Python pass-by-reference or pass-by-value was really helpful.
William Li
Courses Plus Student 26,868 PointsHello, Elizabeth
I'm sure at this point you're familiar with slicing list with index in Python, right?
When you
-
list[1:3]
, you slice out the 2nd and 3rd items from the list -
list[:-1]
, you can leave the beginning index empty, here you slice out every items except the last one. -
list[1:]
, same logic, by leaving the end index out, you slice out every items in the list but the 1st one here.
You can also leave out both the beginning and end index like this list[:]
, that way the thing you slice out is the exact same list as the original one.
Now, the important thing here is that, in Python, the result that comes out from list slicing is actually a new list object in memory. That's why the notion of list[:]
is used very frequently in Python to make a copy of the list.
a = [1,2,3]
b = a[:] # make a copy of a, then assign to b
In the above code, you can safely change the values in b list without effecting a, and vise versa. But please remember this, it doesn't change the fact that b variable is only serves as pointer to a list object, that's just the nature of list assignment in Python, only this time it points to a list that's identical to a, but existed independent to a.
Typed this out in a rush, hope there isn't much error here, also hope that it helps you understand about the topic a little better.
Elizabeth McInerney
3,175 PointsWow, that's fascinating. I don't remember seeing that point raised in any of the videos, but I will remember it now.
So I see also that I was also getting confused by the :, when you see that symbol between {}, it is used in a dictionary to separates the key/value pairs, when you see it between [], it is slicing a list.
William Li
Courses Plus Student 26,868 PointsYep, symbols have different meaning depending on how they were used. For example: the + symbol, when you put it between 2 numbers, it performs addition; but when you put it between 2 Strings, it combines them together.
Also, when writing code in Python, it's important to keep in mind the distinction between pass-by-reference VS pass-by-value; it's best practice not to assign one list to too many variables, because that creates a chain of dependency, you make change in one place, multiple values are effected without your knowledge, this kind of bug can be very hard to trace.