Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
28 views

8 Python Dictionary Things I Regret Not Knowing Earlier

python

Uploaded by

adrian Iosif
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views

8 Python Dictionary Things I Regret Not Knowing Earlier

python

Uploaded by

adrian Iosif
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 8

8 Python Dictionary Things I

Regret Not Knowing Earlier


Liu Zuo Lin

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.

You might also like