These tips have made dealing with dictionaries in Python a lot more enjoyable and elegant, and I kinda wish I learnt them a little less late.
1) Creating a dictionary using dict(key=value)
Note — this is the way that my dev team creates dictionaries 95% of the time. We don’t use {}
very much.
# normal way of creating a dictionary
d = {'apple':4, 'orange':5, 'pear':6, 'pineapple':7}
# 'better' way to creating same dictionary
d = dict(apple=4, orange=5, pear=6, pineapple=7)
Why the better way is a better way:
- when we use
{}
, we need to type the quote characters on string keys - for instance,
'apple'
'orange'
and so on - having to type quote characters becomes exponentially annoying as we have to deal with more and more keys
- when we use
dict()
, we can ignore the quote characters
Of course, the dict()
way doesn’t work with non-string keys, so both ways have their uses.
2) Combining dicts using **
# here are 2 dicts
a = {1:1, 2:2}
b = {3:3, 4:4}
# we can combine them using **
x = {**a, **b}
print(x) # {1:1, 2:2, 3:3, 4:4}
- the
**
in front of the dictionaries unpacks the key-value pairs into the parent dictionary
# we can add normal key-value pairs too
a = {1:1, 2:2}
b = {3:3, 4:4}
x = {**a, **b, 5:5}
print(x) # {1:1, 2:2, 3:3, 4:4, 5:5}
3) We can use ** to pass in a dict as keyword argumets
# a function that takes in a, b, c
def test(a, b, c):
print(a, b, c)
test(a=1, c=2, b=3) # 1 3 2
We can dynamically pass in a dictionary containing the keys a
b
and c
into this function too
mydict = dict(a=1, b=2, c=3)
print(mydict) # {'a':1, 'b':2, 'c':3}
# this is the same as test(a=1, b=2, c=3)
test(**mydict) # 1 2 3
^ the **
in front of the dict once again unpacks its key-value pairs into the function test
Note — this is useful if we want to dynamically pass in keyword arguments into functions.
4) Dictionary comprehension
Let’s say we want to create {1:1, 2:4, 3:9, 4:16}
# normal way to create this
d = {}
for i in range(1, 5):
d[i] = i**2
print(d) # {1: 1, 2: 4, 3: 9, 4: 16}
# dict comprehension way to create this
d = {i:i**2 for i in range(1, 5)}
print(d) # {1:1, 2:4, 3:9, 4:16}
Both are correct and legal ways. But notice that dict comprehension is so much more elegant, Pythonic and easier to read.
# nested for loops
d = {}
for i in range(2):
for j in range(2, 4):
d[(i,j)] = 0
print(d)
# {(0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0}
# nested for loops in dict comprehension
d = {(i,j):0 for i in range(2) for j in range(2, 4)}
print(d)
# {(0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0}
5) dict.get(key, default_value)
When we access a non-existent key, we get KeyError
d = {1:1, 2:2, 3:3}
print(d[1]) # 1
print(d[4]) # KeyError
If we really don’t want a KeyError, we can use the .get()
method instead, which returns None
if our key is non-existent.
# using .get()
d = {1:1, 2:2, 3:3}
print(d.get(1)) # 1
print(d.get(4)) # None
^ notice that instead of raising a KeyError, we get None
instead
# .get() but with custom default value
d = {1:1, 2:2, 3:3}
print(d.get(1, 100)) # 1
print(d.get(4, 100)) # 100
print(d.get(9, 100)) # 100
^ we can define our custom default value too
6) Creating dict() using a list of tuples
# a list of tuples (of length 2)
ls = [('apple', 4), ('orange', 5), ('pear', 6)]
# we can pass this into dict() to create a dict
d = dict(ls)
print(d) # {'apple': 4, 'orange': 5, 'pear': 6}
^ this has been surprisingly useful in quickly creating dictionaries from tuples without having to write dictionary comprehensions.
7) .items() and .values()
# a dict
d = dict(apple=4, orange=5, pear=6)
print(d) # {'apple':4, 'orange':5, 'pear':6}
When we iterate through the dict itself, we simply generate all dict keys:
for k in d:
print(k)
# apple
# orange
# pear
If we use .values()
, we generate all dict values instead:
for v in d.values():
print(v)
# 4
# 5
# 6
If we use .items()
, we generate both key and value as a tuple:
for k,v in d.items():
print(k, v)
# apple 4
# orange 5
# pear 6
^ I myself find .items()
the most useful method here to quickly iterate through all key-value pairs in a dictionary.
8) Stuff that can be dict keys, and stuff that cannot
In general:
- immutable data types can be dict keys eg.
int
str
tuple
bool
- mutable data types cannot eg.
list
dict
# attempt to use immutable data type as dict key
mylist = [1,2,3]
d = {mylist: 5}
# TypeError: unhashable type: 'list'
To legitimately check if some object can be used as a dict key, we can use the built-in hash()
function.
# using hash() on immutable data types
a: int = 4
b: str = 'hi'
print(hash(a)) # 4
print(hash(b)) # -4763374371541057969
# using hash() on mutable data types
l: list = [1, 2, 3]
d: dict = {1:1}
print(hash(l)) # TypeError: unhashable type: 'list'
print(hash(d)) # TypeError: unhashable type: 'dict'
So if you wish to create a custom object that can be a dictionary key, you can use the __hash__
magic method to define how we want to hash our custom object.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
return hash(str(self.name) + str(self.age))
dog1 = Dog('rocky', 4)
dog2 = Dog('fifi', 5)
d = {dog1: 1, dog2: 2}
print(d)
# {<__main__.Dog object at 0x10476a9f0>: 1, <__main__.Dog object at 0x10476aa20>: 2}
Conclusion
Hope this was clear and easy to understand.
If You Wish To Support Me As A Creator
- Buy my book! — 101 Things I Never Knew About Python
- Where to find it: https://ift.tt/5qBW1Am
- Clap 50 times for this story
- Leave a comment telling me your thoughts
- Highlight your favourite part of the story
Thank you! These tiny actions go a long way, and I really appreciate it!
YouTube: https://www.youtube.com/@zlliu246
LinkedIn: https://ift.tt/orTAv8q
Get an email whenever Liu Zuo Lin publishes.
Get an email whenever Liu Zuo Lin publishes. By signing up, you will create a Medium account if you don't already have…
zlliu.medium.com
No comments:
Post a Comment