- How and When Should You Use Defaultdict in Python?
- What Are KeyErrors in Python?
- How to Handle KeyErrors in Python
- #1. Using If-Else Conditional Statements
- #2. Using Try-Except Statements
- #3. Using the .get() Method
- Defaultdict in Python
- Python Defaultdict Examples
- Defaultdict in Python with Default Integer Value
- Defaultdict in Python with List as the Default Value
- Conclusion
- Модуль collections на примерах
- ChainMap
How and When Should You Use Defaultdict in Python?
Invicti Web Application Security Scanner – the only solution that delivers automatic verification of vulnerabilities with Proof-Based Scanning™.
In this tutorial, you’ll learn how to use defaultdict from Python’s collections module—to handle KeyErrors better—when working with Python dictionaries.
In Python, a dictionary is a powerful built-in data structure that stores data in key-value pairs. You’ll use the keys to tap into the dictionary and access the values.
However, when you have multiple dictionaries in your Python script that are modified during code execution, you’ll often run into KeyErrors. And there are a few different ways you can handle them.
In this tutorial, you will learn:
- What KeyErrors are and why they arise
- How to handle KeyErrors
- How to use Python’s defaultdict, a subclass that inherits from the built-in dict class, to handle missing keys better
What Are KeyErrors in Python?
When defining a Python dictionary, you should take care to you should ensure the following:
- The keys should be unique – without any repetition.
- When using an existing iterable as the keys of a dictionary, you should prefer using an immutable collection such as a tuple.
So a key is valid only if it is present in the dictionary; else it leads to KeyErrors.
Consider the following dictionary, books_authors , in which the keys are the names of the books and the values are the names of the authors.
You can code along with this tutorial in a Python REPL.
You can use the key (name of the book) to access the author’s name.
books_authors['Hyperfocus'] 'Chris Bailey'
To access all the key-value pairs in the dictionary, you can call the items() method on the dictionary object, as shown below:
for book,author in books_authors.items(): print(f"'' by ")
'Deep Work' by Cal Newport 'Hyperfocus' by Chris Bailey 'Pivot' by Jenny Blake 'The Happiness Equation' by Neil Pasricha
If you try to access the value of a key that is not present in the dictionary, the Python interpreter raises a KeyError. We run into KeyError when we try to access the value of keys that do not exist, namely, ‘Grit’ and ‘non-existent key’.
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) in ----> 1 books_authors['Grit'] KeyError: 'Grit'
books_authors['non-existent-key']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) in ----> 1 books_authors['non-existent-key'] KeyError: 'non-existent-key'
So how do you handle KeyErrors in Python?
There are few ways to do it, and we’ll learn them in the next section.
How to Handle KeyErrors in Python
Let’s learn how to handle KeyErrors using:
#1. Using If-Else Conditional Statements
One of the most simple ways to handle KeyErrors in Python is using the if-else conditional statements.
In Python, if-else statements have the following general syntax:
if condition: # do this else: # do something else
- If the condition is True , the statements in the if body get executed, and
- If the condition is False , the statements in the else body is executed.
In this example, the condition is to check if the key is present in the dictionary.
If the key is present in the dictionary, the in operator will return True , and if body will be executed printing out the corresponding value.
key = 'The Happiness Equation' if key in books_authors: print(books_authorsCollections import defaultdict python) else: print('Sorry, this key does not exist!') # Output # Neil Pasricha
If the key is not present in the dictionary, the in operator returns False and the else body will be executed. It prints out a message that the key is not present.
key = 'non-existent-key' if key in books_authors: print(books_authorsCollections import defaultdict python) else: print('Sorry, this key does not exist!') # Output # Sorry, this key does not exist!
#2. Using Try-Except Statements
Another common method to handle KeyError is using the try-except statements in Python.
Read through the following code block:
key = 'non-existent-key' try: print(books_authorsCollections import defaultdict python) except KeyError: print('Sorry, this key does not exist!')
- The try block tries to retrieve the value corresponding to the key provided.
- If the key is not present, the interpreter raises a KeyError which is handled as an exception within the except block.
#3. Using the .get() Method
In Python, you can use the built-in dictionary method .get() to handle missing keys.
The general syntax to use the get() method is dict.get(key,default_value) where dict is a valid dictionary object in Python.
– If the key is present in the dictionary, then the get() method returns the value.
– Else, it returns the default value.
In this example, keys is a list of keys whose values we would like to access. We loop through the keys list to retrieve the corresponding values from the books_authors dictionary.
Here, we’ve used the .get() method with ‘Does not exist’ as the default value.
keys = ['Grit','Hyperfocus','Make Time','Deep Work'] for key in keys: print(books_authors.get(key,'Does not exist'))
- For keys that are present in the books_authors dictionary, the .get() method returns the corresponding values.
- When the keys do not exist, in this case, ‘Grit’ and ‘Make Time’, the .get() method returns the default value ‘Does not exist’.
# Output Does not exist Chris Bailey Does not exist Cal Newport
All the above methods help us in handling key errors. However, they are verbose and require us to explicitly handle the missing keys. You can simplify this process by using a defaultdict instead of a regular dictionary.
Defaultdict in Python
The defaultdict is a subclass of the dictionary ( dict ) class. So it inherits the behavior of a Python dictionary. In addition, it also handles missing keys natively.
The defaultdict is a container data type that is built into the Python standard library – inside of the collections module.
So you’ve to import it into your working environment:
from collections import defaultdict
Here’s the general syntax to use defaultdict :
defaultdict(default_factory)
You can specify a callable such as int, float, or list as the default_factory attribute. If you don’t provide a value for the default_factory , it defaults to None .
When the key you’re looking for is not present, the __missing__() method is triggered, and it infers the default value from the default_factory . It then returns this default value.
- In Python, a defaultdict returns the default value when the key is not present.
- It also adds this key-default value pair to the dictionary, which you can then modify.
Python Defaultdict Examples
Next, we’ll code a few examples to understand how Python defaultdict works.
Defaultdict in Python with Default Integer Value
First, import defaultdict from the collections module.
from collections import defaultdict import random
Let us create a defaultdict prices .
We now populate the prices dictionary using the items of the fruits list as the keys. And we randomly sample values from the price_list to get the values.
price_list = [10,23,12,19,5] fruits = ['apple','strawberry','pomegranate','blueberry'] for fruit in fruits: prices[fruit] = random.choice(price_list)
Let’s take a look at the key-value pairs in the prices defaultdict.
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10)])
Like a regular Python dictionary, you can access the values of the prices defaultdict using the keys:
Now, let’s try to access the price of a fruit that is not present, say, ‘orange’. We see that it returns the default value of zero.
If we print out the dictionary, we see that a new key ‘orange’ has been added with the default integer value of zero.
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10), ('orange', 0)])
Defaultdict in Python with List as the Default Value
Let’s define students_majors as a defaultdict of lists. The names of the majors are the keys. And the values are the lists of students pursuing each of the majors, such as math, economics, computer science, and more.
from collections import defaultdict students_majors = defaultdict(list)
If we try to access the student list corresponding to ‘Economics’, defaultdict returns an empty list; no key errors!
We now have an empty list mapped to the ‘Economics’ major. So we can now add elements to this list using the list method .append() .
students_majors['Economics'].append('Alex')
An entry has been created for ‘Economics’ in the students_majors default dictionary.
You can add more students to the list mapping to the Economics major, add a new major, and much more!
students_majors['Economics'].append('Bob') students_majors['Math'].append('Laura') print(students_majors)
Conclusion
I hope this tutorial helped you understand how and when you should use defaultdict in Python. After running the code examples in this tutorial, you can try using defaultdict as the preferred data structure in your projects when needed.
Here is a summary of what you’ve learned in this tutorial.
- When working with a Python dictionary, you’ll often run into KeyErrors.
- To handle such KeyErrors you can use a few verbose methods. You can use conditional statements, try-except blocks, or the .get() method. But the defaultdict data type in the collections module can simplify this KeyError handling.
- You can use defaultdict(default_factory) where default_factory is a valid callable.
- When the key is not present in the defaultdict, the default value (inferred from default_factory) and the key is added to the defaultdict.
Next, check out the tutorial on Python map function.
Модуль collections на примерах
Модуль collections содержит специализированный контейнер типов данных, который может быть использован для замены контейнеров общего назначения Python (dict, tuple, list, и set). Мы изучим следующие части этого замечательного модуля:
Также существует наследованный модуль коллекций под названием abc, или Abstract Base Classes. Мы рассмотрим его в другой раз. Давайте начнем с контейнера ChainMap!
ChainMap
ChainMap – это класс, который дает возможность объединить несколько сопоставлений вместе таким образом, чтобы они стали единым целым. Если вы обратитесь к документации, то увидите, что данный класс принимает **maps*.
Это значит, что ChainMap будет принимать любое количество сопоставлений или словарей и превращать их в единое обновляемое представление. Давайте взглянем на пример, чтобы вы могли увидеть, как это работает:
Здесь мы импортировали ChainMap из модуля collections. Затем мы создали три словаря Python. Далее, мы создали экземпляр ChainMap, передав эти три словаря. В конце мы попытались получить доступ к одному из ключей в нашем ChainMap. После этого, ChainMap пройдет через каждое сопоставление, чтобы увидеть, существует ли данный ключ и имеет ли он значение. Если это так, тогда ChainMap вернет первое найденное значение, которое соответствует ключу. Это весьма полезно в тех случаях, когда вам нужно установить настройки по умолчанию.
Давайте представим, что нам нужно создать приложение, которое имеет определенные настройки по умолчанию. Приложение также будет знать о переменных среды операционной системы. Если существует переменная среды, которая соответствует значению ключа, который расположен в нашем приложении по умолчанию, тогда среда переопределит наши настройки по умолчанию. Теперь давайте представим, что мы можем передавать аргументы нашему приложению. Эти аргументы имеют преимущество над средой и настройками по умолчанию. Это тот случай, когда ChainMap представлен во всей красе. Давайте взглянем на пример, который основан на документации Python:
Давайте немного притормозим. Здесь мы импортировали модуль Python argparse совместно с модулем os. Мы также импортировали ChainMap.Next, простую функцию со слегка нелепыми настройками. Я видел, что эти настройки используются в некоторых популярных роутерах. Далее, мы устанавливаем наш парсер аргументов, и указываем ему, как именно он будет обрабатывать определенные параметры командной строки. Обратите внимание на то, что argparse не предоставляет способ получения объектов словаря или его аргументов, так что мы используем dict для извлечения того, что нам нужно. Здесь мы задействуем встроенный инструмент Python vars. Если вы вызовете его без аргументов, то vars будет вести себя как встроенный locals. Но если передать его объекту, то vars будет выступать в роли эквивалента свойству объекта __dict__. Другими словами, vars(args) равен args.__dict__. В конце мы создаем наш ChainMap, передав аргументы нашей командной строке (если таковые имеются), затем переменные среды и, наконец, настройки. В конце кода, мы пытаемся вызвать нашу функцию, затем устанавливаем переменные среды и снова делаем вызов. Запустите его и увидите, что в выдаче будет admin, и, как и ожидалось, test. Теперь попробуем вызвать скрипт с аргументом командной строки: