找回密码
 会员注册
查看: 37|回复: 0

Pythondefaultdict(可以在访问字典中不存在的键时自动创建默认值)(默认字典、默认值字典)(应用:构建多级字典、模拟类对象动态设置和获取属性、实现图论图结构)(可变字典)

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
73183
发表于 2024-9-4 19:17:31 | 显示全部楼层 |阅读模式
文章目录深入理解Python的defaultdict1.defaultdict简介2.defaultdict的基本语法和初始化1.引入defaultdict2.创建defaultdict对象2.1初始化示例使用list作为默认工厂函数使用int作为默认工厂函数使用set作为默认工厂函数3.访问和修改元素3.1添加和访问元素3.2修改元素4.默认值的行为5.利用工厂函数的灵活性5.1自定义工厂函数示例3.defaultdict的应用场景3.1分组统计示例代码:根据首字母分组单词3.2计数器示例代码:计数列表中元素的出现次数3.3构建多级字典(将`lambda:defaultdict(list)`作为工厂函数)(有点复杂,给我整懵了😨)示例代码:存储学生成绩将`lambda:defaultdict(list)`作为工厂函数的作用4.defaultdict的高级应用4.1使用自定义工厂函数示例代码:使用复杂的默认值4.2动态属性访问(这个也让我有点懵逼😣)示例代码:动态设置和获取属性这个动态设置和获取属性有什么用?1.**代码可读性和简洁性**2.**接口一致性**3.**方便的属性管理**4.**与对象模型的集成**示例解释4.3使用defaultdict实现图结构示例代码:构建无向图的邻接列表关于“无向图的邻接列表”解释代码详解示例输出解释用途5.性能优化和注意事项5.1性能优化5.2注意事项6.总结深入理解Python的defaultdict1.defaultdict简介defaultdict是Python标准库collections模块中的一个类,它扩展了普通字典(dict)的功能。通过使用defaultdict,可以在尝试访问字典中不存在的键时自动创建默认值,这极大地简化了某些编程模式。2.defaultdict的基本语法和初始化在深入探讨defaultdict的高级用法和应用场景之前,理解其基本语法和初始化过程是非常重要的。这有助于确保在实际使用中能够正确且有效地利用defaultdict提供的功能。1.引入defaultdict首先,要使用defaultdict,需要从collections模块中导入它:fromcollectionsimportdefaultdict12.创建defaultdict对象defaultdict的构造函数需要一个参数:一个无参数的工厂函数,该函数决定了当访问不存在的键时,字典应该返回的默认值。2.1初始化示例下面是几种常见的初始化方式:使用list作为默认工厂函数fromcollectionsimportdefaultdict#使用list作为默认工厂函数dd_list=defaultdict(list)dd_list['a'].append(3)dd_list['a'].append(3)dd_list['b'].append('three')print(dd_list)print(type(dd_list))12345678910使用int作为默认工厂函数fromcollectionsimportdefaultdict#使用int作为默认工厂函数dd_int=defaultdict(int)#dd_int['a'].append(2)#报错:AttributeError:'int'objecthasnoattribute'append'dd_int['a']=1dd_int['b']=2dd_int['b']=[3,'aa']#注意用=操作会重设类型print(dd_int)print(type(dd_int))1234567891011使用set作为默认工厂函数fromcollectionsimportdefaultdict#使用set作为默认工厂函数dd_set=defaultdict(set)dd_set['a'].add(2)dd_set['b'].add(3)dd_set['b'].add(4)print(dd_set)print(type(dd_set))123456789103.访问和修改元素defaultdict的行为在很多方面与普通字典相似。你可以像使用普通字典那样添加、修改或访问元素。3.1添加和访问元素#添加元素fromcollectionsimportdefaultdictdd_list=defaultdict(list)dd_list['a'].append(1)dd_list['a'].append(2)#访问元素print(dd_list['a'])#输出:[1,2]#访问不存在的键print(dd_list['b'])#输出:[],自动创建空列表123456789101112133.2修改元素#添加元素fromcollectionsimportdefaultdictdd_int=defaultdict(int)dd_int['key1']=2#增加计数dd_int['key1']+=1print(dd_int['key1'])#输出:1#访问不存在的键,自动初始化为0并加1dd_int['key2']+=1print(dd_int['key2'])#输出:11234567891011121314154.默认值的行为当你访问defaultdict中不存在的键时,defaultdict会自动调用工厂函数来创建一个默认值,并将这个键和默认值作为键值对存入字典。5.利用工厂函数的灵活性可以利用更复杂的工厂函数来实现特定的默认值行为,例如,返回复杂的数据结构或执行更复杂的初始化逻辑。5.1自定义工厂函数示例fromcollectionsimportdefaultdictdefcomplex_factory():return{"count":0,"total":0}dd_complex=defaultdict(complex_factory)print(dd_complex)#defaultdict(,{})print(dd_complex['anything'])#{'count':0,'total':0}print(dd_complex)#defaultdict(,{'anything':{'count':0,'total':0}})#使用自定义默认值dd_complex['product1']['count']+=1dd_complex['product1']['total']+=59.99print(dd_complex['product1'])#输出:{'count':1,'total':59.99}12345678910111213141516171819202122232425了解这些基本语法和概念之后,你就可以更好地理解defaultdict的高级应用,并将其有效地应用在各种编程场景中。3.defaultdict的应用场景3.1分组统计defaultdict特别适用于需要将数据分组的场景。例如,根据某个属性将数据分类并存储到列表中。示例代码:根据首字母分组单词fromcollectionsimportdefaultdictwords=['apple','banana','cherry','date','apricot','blueberry','almond']grouped_words=defaultdict(list)forwordinwords:first_letter=word[0]grouped_words[first_letter].append(word)print(grouped_words)12345678910113.2计数器使用int作为默认工厂函数,可以快速实现一个计数器。示例代码:计数列表中元素的出现次数fromcollectionsimportdefaultdictfruits=['apple','banana','cherry','apple','cherry','cherry','banana']fruit_count=defaultdict(int)forfruitinfruits:fruit_count[fruit]+=1print(fruit_count)123456789103.3构建多级字典(将lambda:defaultdict(list)作为工厂函数)(有点复杂,给我整懵了😨)当需要构建多级字典时,defaultdict的嵌套使用可以避免检查上级字典中键是否存在的麻烦。示例代码:存储学生成绩fromcollectionsimportdefaultdict#grades=defaultdict(lambda:defaultdict(list))grades=defaultdict()#添加数据grades['Class1']['Alice'].append(88)grades['Class1']['Bob'].append(90)grades['Class2']['Charlie'].append(85)print(grades)12345678910111213将lambda:defaultdict(list)作为工厂函数的作用在这段代码中,lambda:defaultdict(list)扮演了非常关键的角色,它是defaultdict构造函数的参数,用作工厂函数。这个工厂函数决定了当访问不存在的键时defaultdict应如何自动创建和初始化其值。当你首次访问一个不存在的键时,例如grades['Class1'],defaultdict需要一个值来与这个键关联。如果没有提供工厂函数,Python将会抛出一个KeyError。但是,通过提供lambda:defaultdict(list),defaultdict会自动调用这个lambda函数来生成一个新的defaultdict(list)作为默认值。这个过程的具体步骤如下:创建defaultdict(list)实例:当lambda被调用时,它创建并返回一个新的defaultdict(list)。这个新的defaultdict用于存储具体的学生名字和其成绩列表。多级嵌套:由于最外层的defaultdict使用了lambda:defaultdict(list)作为工厂函数,当访问如grades['Class1']时,如果‘Class1’不存在,将会创建一个新的defaultdict(list)对象来存储属于‘Class1’的学生和成绩数据。这允许在接下来的操作中,可以直接添加学生名字作为键,成绩列表作为值。简化数据结构操作:这种方式允许代码以非常简洁的形式进行复杂的数据结构操作。例如,grades['Class1']['Alice'].append(88)这行代码在不需要预先检查‘Class1’或‘Alice’是否存在的情况下,直接将88添加到Alice的成绩列表中。如果‘Class1’或‘Alice’不存在,defaultdict会自动创建必要的结构来存储数据。这种使用方式带来的主要优点是代码的简洁性和健壮性,你不需要在每次添加数据前手动检查每个键是否存在,极大地减少了代码的复杂性和出错概率。这对于需要动态添加数据到多层嵌套结构中的场景特别有用,如统计、分组、建立复杂的数据模型等。4.defaultdict的高级应用4.1使用自定义工厂函数除了简单的类型如list、int和set,可以定义更复杂的工厂函数来满足特定的需求。这些工厂函数可以是任何无参数的函数,它返回的值将用作字典的默认值。示例代码:使用复杂的默认值fromcollectionsimportdefaultdictdefdefault_value():return{'count':0,'total':0}complex_default=defaultdict(default_value)#使用默认值进行计算complex_default['item1']['count']+=1complex_default['item1']['total']+=250print(complex_default)123456789101112这种方式特别适合需要初始化多个属性的情况,保证了代码的整洁和易于理解。4.2动态属性访问(这个也让我有点懵逼😣)使用defaultdict可以很方便地实现动态的属性访问,尤其是在处理不确定数据源或灵活构造数据结构时非常有用。示例代码:动态设置和获取属性fromcollectionsimportdefaultdictclassFlexibleDict(defaultdict):def__getattr__(self,key):returnself[key]def__setattr__(self,key,value):self[key]=valueflex_dict=FlexibleDict(int)flex_dict.apple=10print(flex_dict['apple'])#输出10print(flex_dict.orange)#输出0,使用默认int工厂print(flex_dict)#FlexibleDict(,{'apple':10,'orange':0})12345678910111213141516171819这个动态设置和获取属性有什么用?这个示例中的FlexibleDict类通过扩展defaultdict并重写__getattr__和__setattr__方法,使得字典可以像访问对象属性一样方便地设置和获取键值对。这种方式的实用性在于提供了更自然和面向对象的语法来操作字典数据,有几个潜在的用途:1.代码可读性和简洁性使用属性访问方式可以使代码看起来更加整洁和易读。比如,flex_dict.apple比flex_dict['apple']更易于编写和理解,尤其是在处理复杂的数据结构时。2.接口一致性在某些情况下,可能需要将字典与其他使用属性访问的对象一起使用。这种方法可以让字典在语法上表现得和其他对象一致,便于编写统一的代码处理逻辑。3.方便的属性管理重写__getattr__和__setattr__允许在访问或设置属性时加入额外的逻辑,例如验证数据、自动记录修改日志、触发事件等。这在开发某些应用程序时非常有用,可以使字典的行为更加丰富和灵活。4.与对象模型的集成在某些面向对象的设计中,可能需要将字典作为对象属性动态地存取。这种实现使得字典可以无缝地融入面向对象的设计模式中,而不需要修改现有的类结构。示例解释在你提供的代码中,flex_dict的表现如下:使用flex_dict.apple=10设置apple的值为10,这是通过重写的__setattr__方法实现的,内部其实是将apple作为键,10作为值存入字典。使用print(flex_dict['apple'])打印apple的值,显示为10,这是标准字典功能。使用print(flex_dict.orange)查询一个尚未设置的键orange,由于defaultdict使用了int作为默认工厂函数,返回了0,并且现在orange也被设置为0。最后打印flex_dict时,显示其内容和结构,这反映了它同时具备字典的特性和通过属性访问的便利。这种实现提高了字典在某些编程场景中的适用性,尤其是在需要大量动态属性处理的环境中。4.3使用defaultdict实现图结构defaultdict是实现图数据结构中的邻接表的理想选择,可以方便地管理顶点和边。示例代码:构建无向图的邻接列表fromcollectionsimportdefaultdictgraph=defaultdict(set)#添加边graph['A'].add('B')graph['A'].add('C')graph['B'].add('A')graph['C'].add('A')print(graph)1234567891011这样的数据结构非常适合表示复杂的网络关系,如社交网络、交通网等。关于“无向图的邻接列表”解释这段代码使用defaultdict来构建一个无向图的邻接列表。在图论中,邻接列表是图的一种表示方法,其中每个顶点存储一个列表或集合,这个列表或集合包含与之相邻的所有顶点。在这个示例中,使用defaultdict(set)的方式是为了确保每个顶点的邻接顶点不会重复且可以动态增长。代码详解初始化图:graph=defaultdict(set)创建了一个defaultdict,其默认值为一个空的set。这意味着任何尚未明确添加的键(顶点)在首次访问时会自动关联一个新的空集合。添加边:graph['A'].add('B')和graph['A'].add('C')表示顶点‘A’与顶点‘B’和‘C’相连。graph['B'].add('A')表示顶点‘B’与顶点‘A’相连。graph['C'].add('A')表示顶点‘C’与顶点‘A’相连。这些操作通过add方法将相邻顶点添加到各顶点对应的集合中。由于使用的是集合(set),这保证了即便尝试添加重复的边也不会在邻接列表中重复出现相同的顶点。打印图:最后一行print(graph)输出图的邻接列表。由于是无向图,所以每对顶点间的连接在列表中是双向的(例如,‘A’连接到‘B’,同时‘B’也连接到‘A’)。示例输出解释输出可能看起来类似这样:defaultdict(,{'A':{'B','C'},'B':{'A'},'C':{'A'}})1这表示:顶点‘A’与顶点‘B’和‘C’相连。顶点‘B’与顶点‘A’相连。顶点‘C’与顶点‘A’相连。用途这种数据结构的用途非常广泛,适用于需要表示和处理图结构的任何场景,比如社交网络分析、网络拓扑、路径寻找算法、推荐系统等。defaultdict(set)的使用简化了图的构建过程,自动处理了边的添加和重复边的排除,使得代码更简洁、更易于维护。5.性能优化和注意事项5.1性能优化虽然defaultdict提供了方便的默认值管理,但其在处理非常大的数据集时,可能会略微影响性能。在性能敏感的应用中,适当地使用普通字典和手动管理键的存在性可能更加高效。5.2注意事项在使用defaultdict时,如果不需要默认值功能,应考虑回退到普通的字典,以避免不必要的性能损耗。使用自定义工厂函数时,确保它们的逻辑简单且不会引入副作用。6.总结defaultdict在Python中是一个非常强大的工具,特别适合用于需要自动处理缺失键的场景。通过合理使用defaultdict,可以大大简化代码,提高开发效率。不过,应当根据实际需求选择合适的数据结构,以确保程序的性能和可维护性。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-12 18:17 , Processed in 0.493695 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表