Dictionary Methods
You can already fetch a value with d[key] and change one by assigning to it. That is enough for a small dictionary and awkward for everything else — it crashes on a key that is missing, it cannot add several pairs at once, and it cannot take a pair out at all. These are the methods that fill those gaps.
1A dictionary has two columns
Everything in this lesson is easier if you picture a dictionary as two columns rather than one line of text: the keys on the left, the values on the right, one pair per row.
Nearly every method here is answering a question about one column or the other, and the mistakes people make are almost always about reading the wrong column. Keep the two apart in your head and the rest follows.
Every call starts from the same three pairs. Watch which column the answer comes from — and whether the pairs move at all.
marksThe same value that marks['asha'] would give. When the key IS there, get() and the square brackets agree exactly.
2get(): looking up without crashing
Asking for a key that is not there raises a KeyError and stops the program dead. That is the right behaviour when the key should be there — and completely wrong when you are asking precisely because you do not know.
marks = {'ramesh': 87, 'asha': 92}
print(marks.get('asha')) # the key is there
print(marks.get('john')) # not there — no crash
print(marks.get('john', 0)) # not there — use 0 instead
print(marks['john']) # the square brackets do crash92
None
0
Traceback (most recent call last):
File "get.py", line 6, in <module>
print(marks['john']) # the square brackets do crash
~~~~~^^^^^^^^
KeyError: 'john'd[key] and d.get(key) give the same answer whenever the key exists. They differ only on a missing key: the brackets raise a KeyError, get() hands back None — or whatever second argument you gave it.3keys(), values() and items()
These hand you the columns: the left one, the right one, or both together as pairs.
student = {'name': 'Ramesh', 'marks': 87, 'city': 'Delhi'}
print(student.keys())
print(student.values())
print(student.items())dict_keys(['name', 'marks', 'city'])
dict_values(['Ramesh', 87, 'Delhi'])
dict_items([('name', 'Ramesh'), ('marks', 87), ('city', 'Delhi')])The dict_keys(...) wrapper is Python telling you this is a live view of the dictionary rather than a copy of it — change the dictionary and the view changes with it. Notice too that items() gives each row as a tuple of two: the key and its value, travelling together.
list(student.keys()) gives ['name', 'marks', 'city']. These three methods come into their own once loops arrive, which is a later chapter — for now, they are how you look at one column on its own.4Adding and changing: update() and setdefault()
d[key] = value handles one pair at a time. update() does any number of them at once — and it makes no distinction between adding and overwriting. Whether a pair is new or not depends only on whether that key was already there.
marks = {'ramesh': 87, 'asha': 92}
marks.update({'asha': 95, 'chetan': 80})
print(marks){'ramesh': 87, 'asha': 95, 'chetan': 80}One line did two different jobs. 'asha' already existed, so 92 was overwritten with 95 — no second asha row appeared, because keys are unique. 'chetan' did not exist, so it was added.
setdefault() is the careful version: it fills a gap, but it will never overwrite something that is already there. Read the name as the instruction it is — set a default, if there isn't one already.
marks = {'ramesh': 87, 'asha': 92}
print(marks.setdefault('asha', 0)) # already there -> her real mark
print(marks.setdefault('divya', 0)) # missing -> puts her in with 0
print(marks)92
0
{'ramesh': 87, 'asha': 92, 'divya': 0}Asha's 92 survived — the 0 you offered was not used, because it was not needed. Divya was missing, so she was added with the 0 and the 0 was handed back. Either way you end up holding a usable value, which is the point of it.
5Removing: pop(), popitem(), del and clear()
Four ways to take something out, and they differ in what you get back.
student = {'name': 'Ramesh', 'marks': 87, 'city': 'Delhi'}
gone = student.pop('city') # you choose the key; the VALUE comes back
print(gone)
print(student)
last = student.popitem() # the last pair; the whole PAIR comes back
print(last)
print(student)
del student['name'] # a statement, not a method — nothing comes back
print(student)
student.clear() # empty it completely
print(student)Delhi
{'name': 'Ramesh', 'marks': 87}
('marks', 87)
{'name': 'Ramesh'}
{}
{}You choose which pair goes, and you get its value back. A missing key raises a KeyError — unless you give a fallback, like pop('john', 0).
Python chooses — always the last pair — and you get the whole pair back as a tuple. On an empty dictionary it raises a KeyError.
del is not a method. There is no dot and no brackets after it: del student['name'], not student.del('name'). It is an instruction to Python, in the same family as print — and unlike pop(), it hands back nothing at all, so the pair is simply gone.6The functions read the keys
len(), min(), max() and sorted() all work on a dictionary. Look carefully at what they come back with:
marks = {'ramesh': 87, 'asha': 92, 'bilal': 78}
print(len(marks))
print(min(marks))
print(max(marks))
print(sorted(marks))3 asha ramesh ['asha', 'bilal', 'ramesh']
max(marks) is 'ramesh' — the last name alphabetically — even though asha's 92 is the highest number in the whole dictionary. It never looked at the marks at all.This is the single easiest mistake to make with a dictionary, because nothing goes wrong: you asked for a maximum, you got one, and it is the maximum of the wrong column. When you want the values, say so:
marks = {'ramesh': 87, 'asha': 92, 'bilal': 78}
print(max(marks.values()))
print(min(marks.values()))
print(sum(marks.values()))
print(sum(marks.values()) / len(marks))92 78 257 85.66666666666667
And len() is the one that is never ambiguous — it counts the pairs, which is the same number either way.
7copy(): why plain = is not a copy
Give a dictionary a second name and you have not made a second dictionary. Both names point at the same one, so a change through either name shows up in both:
original = {'name': 'Ramesh', 'marks': 87}
same = original # NOT a copy — a second name for the same dictionary
same['marks'] = 100
print(original) # changed, even though we never touched 'original'{'name': 'Ramesh', 'marks': 100}That surprises everybody the first time. copy() is how you get a genuinely separate dictionary — one that can be changed without disturbing the original:
original = {'name': 'Ramesh', 'marks': 87}
backup = original.copy() # a real, separate dictionary
backup['marks'] = 50
print(original)
print(backup){'name': 'Ramesh', 'marks': 87}
{'name': 'Ramesh', 'marks': 50}8Building one: dict() and fromkeys()
dict() is the twin of list() and tuple(): it builds a dictionary out of something else, or out of nothing.
a = dict(name='Ramesh', marks=87) # from key=value pairs
b = dict([('name', 'Ramesh'), ('marks', 87)]) # from a list of tuples
c = dict() # an empty one
print(a)
print(b)
print(c){'name': 'Ramesh', 'marks': 87}
{'name': 'Ramesh', 'marks': 87}
{}fromkeys() is the specialist: hand it a list of keys and one value, and it gives every key that same starting value. It is how you set up a register before anything has been filled in.
names = ['ramesh', 'asha', 'bilal']
marks = dict.fromkeys(names, 0)
print(marks)
print(dict.fromkeys(names)) # no value given -> None for each{'ramesh': 0, 'asha': 0, 'bilal': 0}
{'ramesh': None, 'asha': None, 'bilal': None}fromkeys() is written on dict itself — dict.fromkeys(...) — and not on a dictionary you already have. That is because it is building one from scratch, so there is nothing to write it after.9Try it
10Recap
| Call | Does | Gives back |
|---|---|---|
get(k) | looks up k — no crash if absent | the value, or None |
get(k, d) | looks up k, with a fallback | the value, or d |
keys() | the left column | a view of the keys |
values() | the right column | a view of the values |
items() | both columns, as pairs | a view of (key, value) |
update(d2) | adds and overwrites, many at once | None |
setdefault(k, v) | fills a gap, never overwrites | the value now at k |
pop(k) | removes the pair you name | its value |
popitem() | removes the last pair | the (key, value) tuple |
del d[k] | removes the pair — a statement | nothing |
clear() | empties it completely | None |
copy() | a genuinely separate dictionary | a new dict |
dict(...) | builds one from pairs | a new dict |
dict.fromkeys(ks, v) | every key starts with the same value | a new dict |
len(d) | how many pairs | a number |
min(d) / max(d) / sorted(d) | read the KEYS only | a key / a list of keys |
.values() when you mean the values. And does it change the dictionary? — update(), del and clear() change it and give nothing useful back, while pop(), popitem() and setdefault() do both at once.marks = {'ramesh': 87, 'asha': 92}. What does marks.get('john') give?
marks = {'ramesh': 87, 'asha': 92, 'bilal': 78}. What is max(marks)?
Which one takes out a pair WITHOUT giving you anything back?
marks already has 'asha': 92. What does marks.setdefault('asha', 0) do?