🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # dict字典{} **无序的对象集合** 其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢 ~~~ >>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} >>> d['Michael'] 95 ~~~ 为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。 第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。 dict就是第二种实现方式,给定一个名字,比如'Michael',dict在内部就可以直接计算出Michael对应的存放成绩的“页码”,也就是95这个数字存放的内存地址,直接取出来,所以速度非常快。 key-value存储方式,在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value ## 增 把数据放入dict的方法,除了初始化时指定外,还可以通过key放入: ~~~ >>> d['Adam'] = 67 >>> d['Adam'] 67 ~~~ **setdefault()方法** 此方法是根据函数对字典进行增添元素,参数为(‘key’,‘value’) value默认为none 与直接用 dict[key] = value 的添加元素方法不同,用setdefault(key,value)方法的时候,如果字典没有该key的时候,则会正常添加,如果已经有了该key,那么将不进行操作(不会覆盖原来的值) ~~~ dic = {'name': 'jdxia', 'age': 17} dic.setdefault('name', 'x') dic.setdefault('a', 'b') print(dic) # {'name': 'jdxia', 'age': 17, 'a': 'b'} ~~~ ## 改 由于一个key只能对应一个value,多次对一个key放入value,后面的值会把前面的值冲掉 ~~~ >>> d['Jack'] = 90 >>> d['Jack'] 90 ~~~ ~~~ >>> d['Jack'] = 88 >>> d['Jack'] 88 ~~~ 如果key不存在,dict就会报错: ~~~ >>> d['Thomas'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'Thomas' ~~~ **update({key:value})方法** 该方法是用来追加、拓展原字典元素。 参数必须为一个字典,如下: ~~~ dic = {'name': 'jdxia', 'age': 17} dic.update({'addr': 'a'}) ~~~ 如果传入的字典里有部分key与原字典相同,则该key所对应的值会被覆盖,其他没有的key则会被添加 ## 查 要避免key不存在的错误,有两种办法 **一是通过in判断key是否存在** ~~~ >>> 'Thomas' in d False ~~~ **二是通过dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value** ~~~ >>> d.get('Thomas') >>> d.get('Thomas', -1) -1 ~~~ 注意:返回None的时候Python的交互环境不显示结果 **len()测量字典中,键值对的个数** ![](https://box.kancloud.cn/3669ede2dc7b953e61abdd45af3a9ddb_331x51.png) **keys返回一个包含字典所有KEY的列表** ![](https://box.kancloud.cn/63b81c335c8d6b379111bbdfed71fa99_331x57.png) **values返回一个包含字典所有value的列表** ![](https://box.kancloud.cn/0fc145aeee034ed32eb72de358292881_334x57.png) **items返回一个包含所有(键,值)元祖的列表** ![](https://box.kancloud.cn/561aadfd6dd7fca2af3d1497dc89e644_335x57.png) **has_key dict.has_key(key)如果key在字典中,返回True,否则返回False** ![](https://box.kancloud.cn/ac4ea57630a237bf11d0a9a729f2c732_334x87.png) ## 删 **pop(key)** 与列表的pop()方法不同,字典的pop()方法必须得给它传一个key值,如果字典里没有该key,则会报错。 也可以用 pop(key,'返回值') 来指定返回值,此时,当找不到key的时候,则不会报错,会将指定的返回值返回 删除一个key,用pop(key)方法,对应的value也会从dict中删除 ~~~ >>> d.pop('Bob') 75 >>> d {'Michael': 95, 'Tracy': 85} ~~~ popitem()方法: 此方法类似于列表的pop()方法,用来随机删除一个元素,返回删除的那个元素的(健,值) **del** 删除指定的元素 ~~~ info = {'name':'班长', 'sex':'f', 'address':'地球亚洲中国北京'} print('删除前,%s'%info['name']) del info['name'] print('删除后,%s'%info['name']) ~~~ 删除整个字典 ~~~ info = {'name':'monitor', 'sex':'f', 'address':'China'} print('删除前,%s'%info) del info print('删除后,%s'%info) ~~~ **clear清空整个字典** ~~~ info = {'name':'monitor', 'sex':'f', 'address':'China'} print('清空前,%s'%info) info.clear() print('清空后,%s'%info) ~~~ ## 遍历 ![](https://box.kancloud.cn/3a84f9d86be53ff928aec77a536039e2_376x783.png) ~~~ d = {'a': '1', 'b': '2', 'c': '3'} for k, v in d.items(): # 这种拼接要2边都是字符串 s = k + '---' + v print(s) ~~~ ## 注意 **dict内部存放的顺序和key放入的顺序是没有关系的** 和list比较,dict有以下几个特点: 1. 查找和插入的速度极快,不会随着key的增加而变慢; 2. 需要占用大量的内存,内存浪费多。 而list相反: 1. 查找和插入的时间随着元素的增加而增加; 2. 占用空间小,浪费内存很少。 所以,dict是用空间来换取时间的一种方法。 dict可以用在需要高速查找的很多地方,需要牢记的第一条就是**dict的key必须是不可变对象** 这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。 要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而**list是可变的,就不能作为key**: ~~~ >>> key = [1, 2, 3] >>> d[key] = 'a list' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' ~~~ # set集合{} set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。 ## 增 **创建一个set** ~~~ >>> s = set([1, 2, 3]) >>> s {1, 2, 3} ~~~ 注意,传入的参数`[1, 2, 3]`是一个list,而显示的`{1, 2, 3}`只是告诉你这个set内部有1,2,3这3个元素,显示的顺序也不表示set是有序的。。 重复元素在set中自动被过滤: ~~~ >>> s = set([1, 1, 2, 2, 3, 3]) >>> s {1, 2, 3} ~~~ ~~~ set1 = set({1,2,3,4,5}) set2 = {1,2,3,4,5} set3 = set('abc') print(set1,set2,set3) #{1, 2, 3, 4, 5} {1, 2, 3, 4, 5} {'c', 'b', 'a'} ~~~ ~~~ info = set({"abc": 1, 'a': 2, "cc": "ss"}) print(info) {'a', 'cc', 'abc'} ~~~ **add(key)** 通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果: ~~~ >>> s.add(4) >>> s {1, 2, 3, 4} >>> s.add(4) >>> s {1, 2, 3, 4} ~~~ **update( )方法** 此方法是用来迭代的往集合里添加元素 ~~~ set1 = {1,2,3,4,5} set1.update('6') #不能直接添加数字类型,因为数字类型不可迭代 print(set1) # {1, 2, 3, 4, 5, '6'} set1.update('abc') print(set1) #{1, 2, 3, 4, 5, 'c', 'a', '6', 'b'} set1.update([1,7,8,9]) print(set1) #{1, 2, 3, 4, 5, 'b', 7, 8, 9, 'a', 'c', '6'} ~~~ ## 删 **remove(key)** 通过remove(key)方法可以删除元素: ~~~ >>> s.remove(4) >>> s {1, 2, 3} ~~~ ~~~ set1.remove('2') #指定删除一个元素,找不到就会报错 ~~~ **pop** ~~~ set1 = {1,2,3,4,5} set1.pop() #随机删除一个元素,将元素值返回 ~~~ **clear** ~~~ set1.clear() #清空整个集合 ~~~ **del** ~~~ del set1 #删除整个集合 ~~~ **discard** 删除元素 如果元素不存在,不会做任何操作 也不会报错 ~~~ s.discard('李四') ~~~ ## 查 **for循环** ~~~ set1 = {1,2,3,4,5} for s in set1: print(s) #结果如下: # 1 # 2 # 3 # 4 # 5 ~~~ ## frozenset( )不可变集合 无法添加无法修改 ~~~ set1 = {1,2,3,4,5} set2 = frozenset(set1) print(set2,type(set2)) #结果为:frozenset({1, 2, 3, 4, 5}) <class 'frozenset'> #创建方法如下: set3 = frozenset({1,2,3}) print(set3) # frozenset({1, 2, 3}) set4 = frozenset('abc') #迭代添加 print(set4) # frozenset({'a', 'b', 'c'}) ~~~ ## 集合的交并集操作 ![](https://box.kancloud.cn/6d1f68023e7eb6caec54b17d2f5642de_967x547.png) **交集、并集** set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作: * s1.union(s2) 并集 * s1.intersection(s2) 交集 ~~~ set1 = {1,2,3,7,8} set2 = {2,3,6,9} print(set1&set2) #交集{2, 3} print(set1|set2) #并集{1, 2, 3, 6, 7, 8, 9} print(set1^set2) #反交集{1, 6, 7, 8, 9},就是交集之外的 print(set1-set2) #差集{8, 1, 7} 独有的 print(set2-set1) #差集{9, 6} 独有的 set1 = {1,2,3} #set1为set2的子集 set2 = {1,2,3,4,5} #set2为set1的超集 print(set1 < set2) #判断一个集合是否为另一个集合的子集,用' < '判断 如果是,返回:True ~~~ set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样, 所以,同样**不可以放入可变对象**, 因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。 试试把list放入set,看看是否会报错 **子集和超集** * s1.issubset(s2) s1是否是s2的子集 * s2.issuperset(s1) s2是否是s1的超集 **差集** * s1.difference(s2) **异或** * s1.symmetric_difference(s2) * `s1.symmetric_difference_update(s2)` 更新s1为异或的结果 # copy( )与 deepcopy() 这两种方法用于复制一个变量然后赋值给另一个变量。 copy( )----浅复制 简单来讲,用此方法复制后的变量与原变量对应的内存地址是不一样的,修改它第一层的元素,另一个变量不会被修改 但是如果他们有嵌套(如列表里嵌套列表),那么第二层嵌套的列表与另一个变量所对应的列表的地址就是一个内存地址了, 这个时候,如果修改第二层的元素,则另一个变量也会被修改 用法: ~~~ a = ['a','b','c'] b = a.copy() print(b) #结果为:['a', 'b', 'c'] ~~~ 他们的内存地是不同的,更改一个列表的第一层元素的值,另一个不会被更改,如下: ~~~ li1 = [1,2,[3,4],5] li2 = li1.copy() print(li1 is li2) #False li2[0] = 0 #更改li2第一层的值,li1不会被修改 print(li1) #[1, 2, [3, 4], 5] ~~~ 但是,如果我们要修改一个列表的第二层元素的话,另一个列表就会被修改了,如下: ~~~ li1 = [1,2,[3,4],5] li2 = li1.copy() print(li1 is li2) #False li2[2][0] = 0 #更改li2第二层的值,li1就会被修改 print(li1) #[1, 2, [0, 4], 5] ~~~ **deepcopy( )----深复制** ~~~ import copy li1 = [1,2,[3,4],5] li2 = copy.deepcopy(li1) print(li1 is li2) #False li2[2][0] = 0 #更改li2第二层的值,li1也不会被修改 print(li1) #[1, 2, [3, 4], 5] ~~~