Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Dictionaries and collections.defaultdict

In this lesson, you’ll learn about dictionaries and collections.defaultdict. Dictionaries are a data structure that allows you to store key-value pairs. It allows inserting and retrieving key-value pairs in constant time. collections.defaultdict is a subclass of the dictionary data structure that allows for default values if the key does not exist in the dictionary:

>>>
>>> student_grades = {"Jack": [85, 90], "Jill": [80, 95]}
>>> student_grades["Jack"]
[85, 90]
>>> student_grades.get("Joe", [])
[]
>>> student_grades["Joe"]
KeyError: 'Joe'
>>> student_grades.setdefault("Joe", [])
[]
>>> student_grades["Joe"]
[]
>>> from collections import defaultdict
>>> d = defaultdict(lambda: 10)
>>> d[5]
10
>>> d[5] += 10
>>> d[5]
20

If you want to learn more, check out Dictionaries in Python and Using the Python defaultdict Type for Handling Missing Keys.

00:00 In this video, you’ll learn about dictionaries and defaultdict. Let’s start with the basic old dictionary. student_grades is going to map student names to a list with their grades.

00:12 So, "Jack" has 85 and 90, and "Jill" has 80 and 95.

00:20 Let’s define a function, get_grades_naive(). This is just a basic function that will take in the name and return the student’s grades. So, if name in student_grades: return student_grades[name], otherwise, return an empty list.

00:35 We can run this file, call get_grades_naive() on "Jack"[85, 90]"Jill", and "Joe"—who doesn’t exist in the class—and get an empty list.

00:49 Let’s define get_grades_better(), which is a better version of the function above. Return student_grades and we’ll use the .get() method, which is the same as this except you can pass in a second argument, which will be the default, and then if the name does not exist in student_grades, it will return the default.

01:07 If you do not pass an extra argument in, the default is None, instead of erroring, which this would usually do. Reload the file, just run those same get_grades_better() of "Jack" and "Joe".

01:24 And it works. So now, what if we wanted it so that when you access the grades for a student, it actually binds the empty list to the student and mutates our student_grades, instead of what’s happening here, where it will just return an empty list and not actually change student_grades?

01:41 Let’s do def get_grades_with_assignment(). Usually, in an interview, your function names won’t be so long, but this is just to make it very clear.

01:49 if name not in student grades: student_grades[name] = [], and then return student_grades[name]. Exit here, call get_grades_with_assignment() on "Joe"—who doesn’t exist—and then when we print out student_grades,

02:09 "Joe" exists now in our student_grades. We’ll rewrite this, get_grades_with_assignment_better(),

02:17 and take advantage of the .setdefault() method, which will do exactly that. It will set the default if the key does not exist in our dictionary: .setdefault(name, []).

02:28 So, save…

02:35 That worked, and student_grades changed. So, we’ve written some get functions. Let’s write a function to set the grades. def set_grade_naive(name, score): if name in student_grades: grades = student_grades[name], otherwise, student_grades[name] = [], and then let’s set the grades now to the student_grades[name] and then append to the grades, the score.

03:07 Exit. Let’s set the grades of "Jack" to add 100. student_grades now has a

03:15 100. And let’s say, "Joe" got 100, too. student_grades now includes "Joe" with the list [100]. Of course, we’ll write this better. set_grade_better(name, score), and then take advantage of the fact that we already wrote a function that does a lot of this for us.

03:31 So, you could do something like grades = get_grades_with_assignment_better(name), and then—I’ll wrap my text editor like this. Hopefully, it’s still easy to see that grades is equal to this function call.

03:43 And then, grades.append(score). Save, exit, set_grades_better("Jack", 100), student_grades, and now "Joe", 100—same thing.

03:59 Now, let’s do all this even simpler with the built-in defaultdict. So, defaultdict is part of the collections module, so you have to say from collections import defaultdict and it’s basically what it sounds like—it’s a dictionary, but you can pass in a default value. And then whenever you access a key, if it does not already exist, it will bind to whatever the default is and return it. So down here, let’s reassign student_grades now to be the defaultdict, and the default will be the list().

04:27 Whatever goes in here is going to be a function that will take in no arguments, that when called will return your default value. I’ll go through another example on a little bit regarding this value.

04:38 But anyways, let’s write def set_grade_best(name, score), and now let’s just access the grades for that name and then, .append(score).

04:50 So, a lot is going on here. This syntax works because defaultdict actually inherits from the dict class, and so any syntax you use there will work, and this will check if name exists in student_grades.

05:02 If it does, then return a pointer to that list, otherwise, bind it to the default, and then return a pointer there. Then, .append(score). Let’s exit, save, print out our student_grades. It’s a defaultdict with

05:17 the list() and a dictionary. So, this is a little bit more clear. We have a defaultdict and the list() is our default argument, and then this is our dictionary. Then, we do set_grade_best("Jack", 100).

05:31 This will add "Jack" as a key and 100 to our list. Same with "Joe".

05:37 So, you might be wondering, “Oh, this is a little bit different than up here because here we had existing grades, and here we had no grades and then we had to set grades.” So, that’s actually what the second argument to defaultdict takes in, is a dictionary. So here, you can instantiate the initial dictionary.

05:54 This’ll be a little bit confusing, but we can pass in student_gradeswhich is this dictionary—as the initial dictionary to our now defaultdict, student_grades. And this is because Python evaluates the right-hand side first, looks at this, “Hey, this is our initial dictionary,” passes it in, and then creates a defaultdict from there.

06:15 Save, exit, and look now—student_grades has "Jack" and "Jill". You can access "Jack" just like this,

06:24 and you can set grades just like before.

06:33 So, let’s look at how you can define your own function to pass in as the first argument. Let’s do student_score. So, the score here will actually be the student’s current score in the class, and as they progress through the class, they get more points, or lose points, or something like that.

06:48 And we want to be nice to the students, so we want their initial score to always be 70. So, we do something like this defaultdict(lambda: 70).

07:00 So now, student_score is a defaultdict with a function and no elements. So when we do something like student_score["Jack"] + 10,

07:10 this is going to return 80 because student_score is now going to check, “Is Jack in our dictionary?” It’s not, so return 70 + 10.

07:19 And then what’s interesting here—you print out student_score. 'Jack' still has only 70 because what this did is that set the default value bound to "Jack", but this did not do +=, this just did + and so this just returned 10 + the score.

07:32 If you wanted to actually change Jack’s score, we could do something like += 10, and now 'Jack' has a score of 80.

07:40 We could do this for "Jill", or something, and now "Jill" has this score of 80. defaultdicts are really useful in an interview. Instead of typing five lines of code or making something that might be a little confusing, it’s very clear that defaultdict has a default value and maybe an initial dictionary, and then you can access values and it will bind them to the default value.

08:02 This was a short video on dictionaries and defaultdict. In the next video, you’ll learn more about some useful data structures that are all part of the collections module.

Pygator on April 30, 2020

So all of that is using VS code editor? It looks like a darker jupyter-nb on the side.

James Uejio RP Team on May 8, 2020

Yup it is all VS Code using the “Dainty – Monokai” theme

Abu Shoeb on June 29, 2020

Hi James, I was executing the following piece of code and not getting the same results as yours. Am I missing anything?

student_grades = {
    "Jack" : [85,90],
    "Joe" : [80,95]
}

def get_grade_with_assignment_better(name):
    return student_grades.get(name,[])

def set_grade_better(name,score):
    grades = get_grade_with_assignment_better(name)
    grades.append(score)

set_grade_better("Jack",100)
set_grade_better("Jill",99)

print(student_grades)

Output {'Jack': [85, 90, 100], 'Joe': [80, 95]}

michaljakubiak on Aug. 15, 2020

Btw about this setdefault, you can also append the grades like this. You don’t have to use the defaultdict.

def set_grade(name, grade):
    student_grades.setdefault(name, []).append(grade)

student_grades = {'michal': [5]}
set_grade('michal', 3)
print(student_grades)
set_grade('bob', 3)
print(student_grades)

Output:
{'michal': [5, 3]}
{'michal': [5, 3], 'bob': [3]}

Become a Member to join the conversation.