.get() More with Less from Python Dictionaries
Tags: python, dict, dictionary
Published: 2019-11-21 21:26:21

I recently started volunteering to help host a few interview practice nights for Seattle's local Python user group, [PuPPy (Puget Sound Programming Python)](https://www.pspython.com/app/), and have seen some amazing people coming together to solve whiteboarding problems in the dead of night. During these practice nights I've been delighted by the opportunities I've had to share one of my absolute favorite Python tricks and today I'd like to share it with you.

Have you been in a situation where you needed to store the frequency of keys within a dictionary and have written something similar to this?

```python
# Example 1

s = 'Hello World!'
counts = {}

for char in s:
    try:
        counts[char] += 1
        # Equivalent to counts[char] = counts[char] + 1
    except KeyError:
        counts[char] = 1
```

I don't particularly care for the look of that try/except block. 

The problem here is that dictionaries do not have a default return value when a program uses bracket notation to access a key that is not already present within the dictionary. Instead Python handily crashes the program with a `KeyError`. 

In the case above, if the code in the `try` clause throws a `KeyError` we know that the key is not present in the dictionary. The program then enters the `except` clause where we add the key to the dictionary by explicitly assigning it a value of 1. The next time that key is encountered the `try` clause will not throw an error and the key's value will be incremented by 1.

What if there was a better way, something sleeker, something that doesn't call out that you may be knowingly throwing errors within your code? 

![](https://media.giphy.com/media/j5ElOMw40c0H6uvBtf/giphy.gif)

Well it turns out there is a method within dictionaries that does just that, `.get()`. Calling `.get()` on a dictionary while passing in the desired key will return the value associated with that key, or `None` if the key is not present. This method allows us to modify Example 1 into something a little less hacky in appearance. 

```python
# Example 2

s = 'Hello World!'
counts = {}

for char in s:
    if counts.get(char):
        counts[char] += 1
    else:
        counts[char] = 1
```

That just feels better to look at, right? No errors on this horizon!

Now if the dictionary doesn't contain the key, the default `None` is returned. Since `None` is considered [falsey](https://docs.python.org/3/library/stdtypes.html#truth-value-testing), the code within the `if` clause is not executed and we move into the `else` clause to assign the initial value for the given key. 

Be careful when using `.get()` in logic though, if the value associated with the key is 0, that is also considered falsey and the code within the `if` clause would not execute. It wouldn't make a difference with this specific example but it could in other scenarios. In those cases I would suggest something along the lines of `if counts.get(char) != None:` to check if the value associated with the key is anything other than `None`.

:thinking: Hmm, but Example 2 doesn't seem to have any less lines of code than Example 1. Well, there's more goodness stashed away in `.get()`. This method also accepts an optional second argument that defines the default return value. Not satisfied with `None`? Then let's do something about it!

```python
# Example 3

s = 'Hello World!'
counts = {}

for char in s:
    counts[char] = counts.get(char, 0) + 1
```

![](https://media.giphy.com/media/11jIcdl19gWkAE/giphy.gif)

It's... beautiful! 

A lot is happening on that last line. The `.get()` method checks the dictionary for the given key and returns either the value associated with the key or the default return value we specified as the second argument, 0. We add 1 to whatever is returned from `.get()`, assign the sum as the value for the key, and call it a day.

The examples above have dealt with a simple counting scenario but `.get()` can be used practically anywhere you're checking keys in a dictionary. If you're specifically in the counting business, I'd recommend you that you also take a peek at the incredible [`Counter`](https://docs.python.org/3.7/library/collections.html#collections.Counter) class from the Python Standard Library's `collections` module.

```python
# Example 4

from collections import Counter

counts = Counter('Hello World!')
```

Thank you for reading my love letter to `.get()`! Let me know how you've used `.get()` or if you know a Python trick that you feel everyone should be embracing.

:wave: