在Python中,defaultdict
是一个类似于字典的类collections
模块允许我们为字典中未显式设置的键定义默认值。它是内置的子类dict
class.
Both dict
and defaultdict
用于以键值对格式(Python 中称为字典)存储和管理数据。
在本教程中,我们将探索 defaultdict 的各种功能和用例,了解它与标准词典的差异。
dict 和 defaultdict 之间的区别
主要区别在于,常规字典在访问不存在的键时会抛出错误,而 defaultdict 返回默认值。
让我们用普通字典来考虑这个场景:
regular_dict = dict()
print(regular_dict['non_existent_key'])
Output:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'non_existent_key'
上面的代码引发了一个KeyError
回溯,因为字典中不存在键“non_existent_key”。这是哪里defaultdict
进来。
default_dict = defaultdict(int)
print(default_dict['non_existent_key'])
Output:
0
如果是defaultdict
,当我们尝试访问字典中不存在的键时,而不是KeyError
,defaultdict 返回默认工厂函数设置的默认值(在本例中,int
这意味着默认值为0
).
创建默认字典
要创建defaultdict,我们需要从collections模块导入defaultdict类。
构造函数接受一个函数作为参数,该函数为字典提供默认值。
这是一个简单的例子:
from collections import defaultdict
# Initializing defaultdict with int
dd_int = defaultdict(int)
print(dd_int)
# Initializing defaultdict with list
dd_list = defaultdict(list)
print(dd_list)
Output:
defaultdict(<class 'int'>, {})
defaultdict(<class 'list'>, {})
在此代码中,我们创建了两个 defaultdict 实例:dd_int
with int
作为默认工厂函数和dd_list
with list
作为默认工厂函数。
打印时,每个实例都会显示其默认工厂函数及其当前数据,这是一个空字典。
默认工厂功能
Python提供了几个可以用作默认工厂的内置函数,例如list()
, int()
, set()
, dict()
, str()
, float()
, bool()
, and tuple()
.
让我们探讨其中的一些:
# Default factory function is list
dd_list = defaultdict(list)
dd_list['key1'].append(1)
print(dd_list)
# Default factory function is int
dd_int = defaultdict(int)
dd_int['key1'] += 1
print(dd_int)
# Default factory function is set
dd_set = defaultdict(set)
dd_set['key1'].add(1)
print(dd_set)
# Default factory function is dict
dd_dict = defaultdict(dict)
dd_dict['key1']['inner_key1'] = 1
print(dd_dict)
# Default factory function is str
dd_str = defaultdict(str)
dd_str['key1'] += 'a'
print(dd_str)
Output:
defaultdict(<class 'list'>, {'key1': [1]})
defaultdict(<class 'int'>, {'key1': 1})
defaultdict(<class 'set'>, {'key1': {1}})
defaultdict(<class 'dict'>, {'key1': {'inner_key1': 1}})
defaultdict(<class 'str'>, {'key1': 'a'})
在上面的示例中,我们使用了不同的默认工厂函数。和list
,当我们尝试将元素附加到未知键时,它会自动创建一个空列表并附加该项目。同样,与int
,它将值初始化为 0 并加 1。
With set
,它为未知键创建一个空集。和dict
,它为未知键创建一个空字典。
最后,与str
,它初始化一个空字符串并向其附加字符串“a”。
使用自定义默认函数创建 defaultdict
除了内置函数之外,您还可以传递自定义函数作为默认工厂。
from collections import defaultdict
# Define a function that will be used as the default factory
def my_func():
return 'Default Value'
# Create a defaultdict with the custom default factory
dd = defaultdict(my_func)
# Access a key that doesn't exist
print(dd['non_existent_key'])
Output:
Default Value
在这段代码中,我们首先定义一个自定义函数my_func
返回“默认值”。然后我们创建一个defaultdictdd
, 通过my_func
作为论点。
当我们尝试访问 defaultdict 中不存在的键时,它会返回我们的自定义默认工厂函数返回的值,即“默认值”。
带有 Lambda 的 defaultdict
我们可以使用 lambda 函数作为 defaultdict 中的默认工厂。 lambda 函数是一个小型匿名函数,它使用lambda
关键词。
让我们使用 lambda 函数创建一个 defaultdict,该函数返回字符串“default”作为默认值。
from collections import defaultdict
# Create a defaultdict with lambda as default factory
dd = defaultdict(lambda: 'default')
print(dd['missing_key'])
Output:
default
在这个例子中,我们创建一个defaultdictdd
,传递 lambda 函数作为参数。该 lambda 函数在调用时返回字符串“default”。
当我们尝试访问丢失的键“missing_key”时,defaultdict 不会引发KeyError
。相反,它调用 lambda 函数来提供默认值,因此返回“default”。
访问defaultdict中的元素
就像普通字典一样,您可以使用键访问 defaultdict 中的元素。您还可以使用get()
方法,这是dict类的内置方法。
from collections import defaultdict
# Create a defaultdict with default factory int
dd = defaultdict(int)
# Add some elements
dd['key1'] = 10
dd['key2'] = 20
# Accessing elements using keys
print(dd['key1'])
print(dd['key2'])
# Accessing elements using get() method
print(dd.get('key1'))
print(dd.get('key2'))
Output:
10
20
10
20
在这段代码中,我们首先创建一个defaultdictdd
with int
作为默认工厂函数。然后我们向 defaultdict 添加一些元素。
当我们使用元素的键或get()
方法,它返回相应的值。
如果您使用get()
方法的键不存在,它将返回None
代替KeyError
.
print(dd.get('non_existent_key'))
Output:
None
The get()
这里的方法与标准字典中的方法类似,返回None
当键不存在时而不是默认的工厂值。
添加新元素
向 defaultdict 添加新元素非常简单。就像使用标准字典一样,您可以使用赋值操作。
from collections import defaultdict
# Create a defaultdict with default factory list
dd = defaultdict(list)
# Add a new element
dd['key1'].append('Python')
print(dd)
Output:
defaultdict(<class 'list'>, {'key1': ['Python']})
在这个例子中,我们首先创建一个defaultdictdd
with list
作为默认工厂函数。然后我们使用键“key1”向 defaultdict 添加一个新元素。
由于默认工厂函数是list
,我们可以直接使用append函数将值‘Python’添加到‘key1’对应的列表中。
更新现有元素
您可以直接为现有键分配新值:
from collections import defaultdict
dd = defaultdict(int)
dd['key1'] = 10
print(dd)
dd['key1'] = 20
print(dd)
Output:
defaultdict(<class 'int'>, {'key1': 10})
defaultdict(<class 'int'>, {'key1': 20})
在这个例子中,我们首先创建一个defaultdictdd
with int
作为默认工厂函数。然后我们添加一个以“key1”为键的新元素10
作为值。
要更新元素,我们只需分配一个新值20
到相同的键“key1”。最终的默认字典有“key1”20
作为它的价值。
defaultdict 如何处理丢失的键?
A defaultdict
工作原理与常规字典完全相同,但它是用函数初始化的(default_factory
函数),不带参数并为不存在的键提供默认值。
如果您访问的密钥不存在于defaultdict
,它将调用它的default_factory
函数并将结果用作该键的新值。
此行为由__missing__
method.
在标准字典中,__missing__
方法用于处理丢失的键。当未找到密钥时,Python 将密钥作为参数发送给__missing__
方法(如果已实现)而不是提出KeyError
.
但是,那defaultdict
覆盖这个__missing__
处理丢失钥匙的方法。
If the default_factory
属性是None
,这提出了KeyError
以参数为键的异常。
If default_factory
is not None
,不带参数调用它来为给定键提供默认值,该值将插入到键的字典中并返回。
这是一个例子:
from collections import defaultdict
# Function to return a default value for missing keys
def default_factory():
return 'Default Value'
ddict = defaultdict(default_factory)
print(ddict['key1']) # key1 does not exist in the dictionary
Output:
Default Value
在这个例子中,key1
字典中不存在。当我们尝试访问时key1
, defaultdict
称其为default_factory
功能、插入key1
将返回的值放入字典中default_factory
,然后返回该值。因此,一个defaultdict
从不提出KeyError
.
嵌套默认字典
嵌套defaultdict是包含其他defaultdict作为值的defaultdict,它允许您创建字典的字典(甚至更复杂的结构)。
创建嵌套的defaultdict
以下是创建嵌套 defaultdict 的方法:
from collections import defaultdict
# Function to return a defaultdict with int as default factory
def nested_dd():
return defaultdict(int)
# Create a nested defaultdict
dd = defaultdict(nested_dd)
# Add values to the nested defaultdict
dd['key1']['inner_key1'] += 1
dd['key1']['inner_key2'] += 2
dd['key2']['inner_key1'] += 3
print(dd)
Output:
defaultdict(<function nested_dd at 0x7f15c3f7edc0>, {'key1': defaultdict(<class 'int'>, {'inner_key1': 1, 'inner_key2': 2}), 'key2': defaultdict(<class 'int'>, {'inner_key1': 3})})
在这段代码中,我们首先定义一个函数nested_dd
返回一个defaultdictint
作为默认工厂函数。
然后我们创建一个defaultdictdd
, 通过nested_dd
作为论点。
当我们向嵌套的defaultdict添加值时,如果键不存在,defaultdict会自动创建它们并使用默认值(在本例中为0)初始化它们。
嵌套 defaultdict 的实际用例
处理复杂的数据结构时,嵌套的 defaultdict 会很有用。
例如,它可用于表示树或图,其中每个节点都是一个字典,其中键表示连接的节点,值表示连接的权重。
让我们考虑一个实际用例:您正在使用代表电子商务商店销售的数据。该数据包含有关按年、月和产品类别分组的销售额的信息。
我们可以使用嵌套的 defaultdict 来有效地组织和访问这些数据。
from collections import defaultdict
# Function to return a defaultdict with float as default factory
def nested_dd():
return defaultdict(float)
# Create a nested defaultdict for sales data
sales = defaultdict(lambda: defaultdict(nested_dd))
# Add values to the nested defaultdict
sales[2022]['January']['Electronics'] = 12000.50
sales[2022]['January']['Books'] = 3500.25
sales[2022]['February']['Electronics'] = 10500.75
sales[2023]['March']['Books'] = 5000.00
print(sales)
Output:
defaultdict(<function <lambda> at 0x7f15c3f7edc0>, {2022: defaultdict(<function nested_dd at 0x7f15c3f7ee50>, {'January': defaultdict(<class 'float'>, {'Electronics': 12000.5, 'Books': 3500.25}), 'February': defaultdict(<class 'float'>, {'Electronics': 10500.75})}), 2023: defaultdict(<function nested_dd at 0x7f15c3f7ee50>, {'March': defaultdict(<class 'float'>, {'Books': 5000.0})})})
在这个例子中,我们首先定义一个函数nested_dd
返回一个defaultdictfloat
作为默认工厂函数。
然后我们创建一个defaultdictsales
,传递一个返回由以下命令创建的defaultdict的函数nested_dd
作为论点。
这给了我们一个三层嵌套的defaultdict。然后我们将销售数据添加到 defaultdict 中。
第一级键代表年份,第二级键代表月份,第三级键代表产品类别。
这些值代表销售额。
这种结构使我们能够轻松获取特定产品类别在特定年份的特定月份的销售额。
例如,sales[2022]['January']['Electronics']
将返回 2022 年 1 月电子产品的销售额。
defaultdict 方法
defaultdict 支持标准 Python 字典提供的所有方法。
方法如keys()
, values()
, items()
, get()
, pop()
, clear()
以及许多其他词典,都与 defaultdicts 一起工作,就像它们与标准词典一样。
让我们看一些例子:
from collections import defaultdict
dd = defaultdict(int)
dd['key1'] = 10
dd['key2'] = 20
# Print all keys
print(dd.keys())
# Print all values
print(dd.values())
# Print all items
print(dd.items())
# Get the value of a key
print(dd.get('key1'))
# Remove and return a key-value pair
print(dd.pop('key1'))
print(dd)
Output:
dict_keys(['key1', 'key2'])
dict_values([10, 20])
dict_items([('key1', 10), ('key2', 20)])
10
10
defaultdict(<class 'int'>, {'key2': 20})
所有这些方法都按预期工作。他们对 defaultdict 执行操作就像对标准字典执行操作一样。
defaultdict (default_factory) 特有的特殊方法
此方法返回用于创建默认值的函数。
print(dd.default_factory)
Output:
<class 'int'>
Here, default_factory
回报<class 'int'>
,这是我们用来生成 defaultdict 默认值的函数。
迭代defaultdict
迭代 defaultdict 与迭代标准字典类似。您可以迭代键、值或项目(键值对)。
迭代键
from collections import defaultdict
dd = defaultdict(int)
dd['key1'] = 10
dd['key2'] = 20
# Iterate over keys
for key in dd:
print(key)
Output:
key1
key2
在此示例中,我们创建一个带有两个键的 defaultdict:“key1”和“key2”。然后我们使用简单的 for 循环迭代键。这会将每个键打印在单独的行上。
迭代值
for value in dd.values():
print(value)
Output:
10
20
我们使用values()
defaultdict 的方法来获取所有值的可迭代,然后在单独的行上打印每个值。
迭代项目(键值对)
for key, value in dd.items():
print(f'{key}: {value}')
Output:
key1: 10
key2: 20
The items()
defaultdict 的方法返回一个可迭代的元组,其中每个元组包含一个键值对。
排序默认字典
您可以使用sorted()
返回排序键或值列表的函数。
按键排序
from collections import defaultdict
dd = defaultdict(int)
dd['banana'] = 10
dd['apple'] = 20
dd['cherry'] = 15
# Sort by keys
sorted_dd = sorted(dd.items())
print(sorted_dd)
Output:
[('apple', 20), ('banana', 10), ('cherry', 15)]
在此示例中,我们创建一个包含三个键的默认字典:“banana”、“apple”和“cherry”。然后我们使用sorted
功能与dd.items()
作为论点。
这按键对项目进行排序并返回元组列表,其中每个元组包含一个键值对。该列表按键升序排序。
按值排序
sorted_dd = sorted(dd.items(), key=lambda x: x[1])
print(sorted_dd)
Output:
[('banana', 10), ('cherry', 15), ('apple', 20)]
我们使用sorted
功能与dd.items()
and a key
函数作为参数。
The key
function 是一个 lambda 函数,它返回元组的第二个元素(键值对的值),因此sorted
函数按值对项目进行排序。
defaultdict 用法的真实示例
表示图数据结构
一个常见的用例defaultdict
是表示一个图数据结构,其中键是节点,值是相邻节点的列表。
假设我们正在构建一个简单的社交网络,我们想要表示不同用户之间的朋友联系。
我们可以使用以下方法来做到这一点defaultdict
:
from collections import defaultdict
# Each pair represents a connection between two users
friend_connections = [('Anna', 'Beth'), ('Anna', 'Chad'), ('Beth', 'Dave'), ('Chad', 'Dave'), ('Dave', 'Emily'), ('Emily', 'Frank'), ('Frank', 'Anna')]
# Initialize our graph with a defaultdict of type list
friend_graph = defaultdict(list)
# Populate the graph
for user1, user2 in friend_connections:
friend_graph[user1].append(user2)
friend_graph[user2].append(user1) # Add this line if the friendship is mutual
# Print friend connections of each user
for user, friends in friend_graph.items():
print(f"{user} is friends with {', '.join(friends)}")
Output:
Anna is friends with Beth, Chad, Frank
Beth is friends with Anna, Dave
Chad is friends with Anna, Dave
Dave is friends with Beth, Chad, Emily
Emily is friends with Dave, Frank
Frank is friends with Emily, Anna
这样,我们就可以轻松地表示复杂的数据结构,例如图形defaultdict
.
计算词频
defaultdict 在自然语言处理或文本分析领域的另一个常见用例是计算文档或文档集合中单词的频率。
这个想法是创建一个默认字典,默认工厂为int
并使用文档中的每个单词作为键。
defaultdict 会自动处理缺失的键并返回默认值 0。
让我们编写一个小脚本来演示这一点:
from collections import defaultdict
text = """
The Python defaultdict type is a dictionary-like class available in Python's collections module.
Unlike standard Python dictionaries, defaultdict lets you specify a default value type at the
time of its creation. When you try to access or modify keys in the defaultdict that do not exist,
instead of a KeyError, you get a default value of the type you specified during creation.
The defaultdict type is useful in situations where you want to avoid unnecessary KeyError exceptions
and make your code more readable and clean. It's especially handy when working with collections of
data where some keys might not exist.
"""
word_freq = defaultdict(int)
# Normalize the text
normalized_text = text.lower().split()
# Count the frequency of each word
for word in normalized_text:
word_freq[word] += 1
for word, freq in word_freq.items():
print(f'Word: {word}, Frequency: {freq}')
Output:
Word: the, Frequency: 5
Word: python, Frequency: 2
Word: defaultdict, Frequency: 4
Word: type, Frequency: 4
Word: is, Frequency: 2
Word: a, Frequency: 4
Word: dictionary-like, Frequency: 1
Word: class, Frequency: 1
Word: available, Frequency: 1
Word: in, Frequency: 3
Word: python's, Frequency: 1
Word: collections, Frequency: 2
Word: module., Frequency: 1
Word: unlike, Frequency: 1
Word: standard, Frequency: 1
Word: dictionaries,, Frequency: 1
Word: lets, Frequency: 1
Word: you, Frequency: 5
Word: specify, Frequency: 1
Word: default, Frequency: 2
Word: value, Frequency: 2
Word: at, Frequency: 1
Word: time, Frequency: 1
Word: of, Frequency: 4
Word: its, Frequency: 1
Word: creation., Frequency: 2
Word: when, Frequency: 2
Word: try, Frequency: 1
Word: to, Frequency: 2
Word: access, Frequency: 1
Word: or, Frequency: 1
Word: modify, Frequency: 1
Word: keys, Frequency: 2
Word: that, Frequency: 1
Word: do, Frequency: 1
Word: not, Frequency: 2
Word: exist,, Frequency: 1
Word: instead, Frequency: 1
Word: keyerror,, Frequency: 1
Word: get, Frequency: 1
Word: specified, Frequency: 1
Word: during, Frequency: 1
Word: useful, Frequency: 1
Word: situations, Frequency: 1
Word: where, Frequency: 2
Word: want, Frequency: 1
Word: avoid, Frequency: 1
Word: unnecessary, Frequency: 1
Word: keyerror, Frequency: 1
Word: exceptions, Frequency: 1
Word: and, Frequency: 2
Word: make, Frequency: 1
Word: your, Frequency: 1
Word: code, Frequency: 1
Word: more, Frequency: 1
Word: readable, Frequency: 1
Word: clean., Frequency: 1
Word: it's, Frequency: 1
Word: especially, Frequency: 1
Word: handy, Frequency: 1
Word: working, Frequency: 1
Word: with, Frequency: 1
Word: data, Frequency: 1
Word: some, Frequency: 1
Word: might, Frequency: 1
Word: exist., Frequency: 1
该代码将输出每个单词的频率。这些单词不区分大小写,因为我们使用lower
函数来规范化文本。
The split()
函数用于根据空格将文本分成单词。
资源
https://docs.python.org/3/library/collections.html#collections.defaultdict