dict 字典
字典是另一种可变容器模型,且可存储任意类型对象。
Python内置了字典:dict
的支持,dict全称dictionary,在其他语言中也称为map
,使用键-值(key-value)存储,具有极快的查找速度。每个键值对用冒号:
分割,每个对之间用逗号,
分割,整个字典包括在花括号{ }
中
d = {key1 : value1, key2 : value2 }
键必须是唯一的,但值则不必。
值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。
一个简单的字典实例:
dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
也可如此创建字典:
dict1 = { 'abc': 456 }; dict2 = { 'abc': 123, 98.6: 37 };
还有dict函数创建方式,注意这里的Key不能使用引号,否则会出错
>>> dict3 = dict(A='AA',B='BB') >>> dict3 {'A': 'AA', 'B': 'BB'} >>> dict3 = dict('A'='AA','B'='BB') SyntaxError: keyword can't be an expression >>>
为什么dict查找速度这么快?
因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。
第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。
dict就是第二种实现方式,将Key存入内存中,相当于书本的“页码”,根据“页码”取值,相当快。
访问dict字典里的值
把相应的键放入熟悉的方括弧,如下实例:
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} print ("dict['Name']: ", dict['Name']) print ("dict['Age']: ", dict['Age'])
以上实例输出结果:
dict['Name']: Runoob dict['Age']: 7
如果用字典里没有的键访问数据,会输出错误如下:
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}; print ("dict['Alice']: ", dict['Alice']) 输出结果: Traceback (most recent call last): File "test.py", line 5, in <module> print ("dict['Alice']: ", dict['Alice']) KeyError: 'Alice'
也可以使用get方法来获取数据,如下操作,当get的key不存在时候,返回None,存在时放回对象值
>>> dict1 = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} >>> dict1 {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} >> print(dict1.get('AA')) None >>> dict1.get('Name') 'Runoob'
如下操作:如果在get时,没有此key,可以自定义返回值;有key值就返回key值。
>>> dict1.get('AA','No Data!') 'No Data!' >>> dict1.get('Name','No Data!') 'Runoob'
修改dict字典
向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} dict['Age'] = 10; # 更新 Age dict['School'] = "程序喵" # 添加信息 print ("dict['Age']: ", dict['Age']) print ("dict['School']: ", dict['School']) 以上实例输出结果: dict['Age']: 10 dict['School']: 程序喵
删除dict字典元素
能删单一的元素也能清空字典,清空只需一项操作。
显示删除一个字典用del和pop(key)
命令,如下实例:
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} del dict['Name'] # 删除键 'Name' dict.clear() # 删除字典 del dict # 删除字典 print ("dict['Age']: ", dict['Age']) print ("dict['School']: ", dict['School'])
但这会引发一个异常,因为用执行 del
操作后字典不再存在:
Traceback (most recent call last): File "test.py", line 9, in <module> print ("dict['Age']: ", dict['Age']) TypeError: 'type' object is not subscriptable
要删除一个key,用pop(key)
方法,对应的value也会从dict中删除:删除时值将回返回
>>> d.pop('Bob') 75 >>> d {'Michael': 95, 'Tracy': 85} >>>
要避免key不存在的错误,有两种办法,
通过
in
判断key是否存在;通过dict提供的
get
方法,如果key不存在,可以返回None,或者自己指定的value:
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} >>> d.get('Anson') >>> print(d.get('Anson')) None >>> d.get('Aimi', -1) -1 >>> 'Anson' in d False >>>
注意:返回None
的时候Python的交互式命令行不显示结果。但是可以借助print
函数输出
dect字典键的特性
字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行。
1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住,如下实例:
x = {'Name': 'Runoob', 'Age': 7, 'Name': '程序喵'} print ("x['Name']: ", x['Name']) 输出结果: dict['Name']: 程序喵
2)键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行,如下实例:
>>> x={(10,):"Anson","Age":22} >>> x.values() dict_values(['Anson', 22]) >>> x.popitem() ((10,), 'Anson') >>> >>> x = {['Name']: 'Anson', 'Age': 7} Traceback (most recent call last): File "<pyshell#37>", line 1, in <module> x = {['Name']: 'Anson', 'Age': 7} TypeError: unhashable type: 'list'
请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。
和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
而list相反:
查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,这就是为什么不能作为key的原因
字典内置函数&
方法,不同版本内容不同,建议使用help函数查看所有
Python字典包含了以下内置函数:
序号 | 函数及描述 | 实例 |
---|---|---|
1 | len(dict) 计算字典元素个数,即键的总数。 | >>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} >>> len(dict) 3 |
2 | str(dict) 输出字典,以可打印的字符串表示。 | >>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} >>> str(dict) "{'Name': 'Runoob', 'Class': 'First', 'Age': 7}" |
3 | type(variable) 返回输入的变量类型,如果变量是字典就返回字典类型。 | >>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'} >>> type(dict) <class 'dict'> |
Python字典包含了以下内置方法:
序号 | 函数及描述 |
---|---|
1 | radiansdict.clear() 删除字典内所有元素 |
2 | radiansdict.copy() 返回一个字典的浅复制 |
3 | radiansdict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
4 | radiansdict.get(key, default=None) 返回指定键的值,如果值不在字典中返回default值 |
5 | key in dict 如果键在字典dict里返回true,否则返回false |
6 | radiansdict.items() 以列表返回可遍历的(键, 值) 元组数组 |
7 | radiansdict.keys() 以列表返回一个字典所有的键 |
8 | radiansdict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
9 | radiansdict.update(dict2) 把字典dict2的键/值对更新到dict里 |
10 | radiansdict.values() 以列表返回字典中的所有值 |
11 | pop(key[,default]) 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。 |
12 | popitem() 随机返回并删除字典中的一对键和值。 |
formkeys函数使用
Python 字典 fromkeys() 函数用于创建一个新字典,以序列seq中元素做字典的键,value为字典所有键对应的初始值。
语法:dict.fromkeys(seq[, value]))
参数
seq:字典键值列表。
value:可选参数, 设置键序列(seq)的值。
返回值:该方法返回列表。
>>> dict1 = {} >>> dict1.fromkeys((1,2,3)) {1: None, 2: None, 3: None} >>> dict1.fromkeys((1,2,3),'Number') {1: 'Number', 2: 'Number', 3: 'Number'} >>> dict1.fromkeys(('Name','Age','Love'),('Anson',22,'girl')) {'Name': ('Anson', 22, 'girl'), 'Age': ('Anson', 22, 'girl'), 'Love': ('Anson', 22, 'girl')}
copy函数
copy是直接将一个对象拷贝到另外一个对象上面,经过发现,直接使用等于号赋值存在相同id地址,与copy存在不同的引用地址
>>> a = {'Name':'Anson','Age':22} >>> a {'Name': 'Anson', 'Age': 22} >>> b = a >>> b {'Name': 'Anson', 'Age': 22} >>> id(a) 4313730864 >>> id(b) 4313730864 >>> >>> c = a.copy() >>> c {'Name': 'Anson', 'Age': 22} >>> id(c) 4394891088
set 集合
集合(set)是一个无序不重复元素的序列。所以没有get和index这类索引操作方法。
set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key
可以使用大括号 { }
或者 set()
函数创建集合,注意:创建一个空集合必须用 set()
而不是 { }
,因为 { }
是用来创建一个空字典。
要创建一个set,需要提供一个list作为输入集合:
>>> 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}
添加集合
通过add(key)
方法可以添加元素到set中,可以重复添加,但不会有效果:
>>> s.add(4) >>> s {1, 2, 3, 4} >>> s.add(4) >>> s {1, 2, 3, 4}
删除集合
通过pop()、remove(key)、del()
方法可以删除元素:pop命令会将删除的值返回出来。 del命令会将整个集合删除
>>> s.remove(4) >>> s {1, 2, 3} >>> s.pop() 1 >>> s {2, 3} >>> s.r
set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
>>> s1 = set([1, 2, 3]) >>> s2 = set([2, 3, 4]) >>> s1 & s2 {2, 3} >>> s1 | s2 {1, 2, 3, 4}
set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象
扩展示例
student = {'Tom', 'Jim', 'Mary', 'Tom', 'Jack', 'Rose'} print(student) # 输出集合,重复的元素被自动去掉 # 成员测试 if('Rose' in student) : print('Rose 在集合中') else : print('Rose 不在集合中') # set可以进行集合运算 a = set('abracadabra') b = set('alacazam') print("a:", a) print("b:", b) print("a和b的差集:", a - b) # a和b的差集 print("a和b的并集:", a | b) # a和b的并集 print("a和b的交集:", a & b) # a和b的交集 print("a和b中不同时存在的元:", a ^ b) # a和b中不同时存在的元 输出 {'Jim', 'Jack', 'Tom', 'Mary', 'Rose'} Rose 在集合中 a: {'b', 'a', 'd', 'r', 'c'} b: {'a', 'z', 'l', 'c', 'm'} a和b的差集: {'b', 'r', 'd'} a和b的并集: {'b', 'a', 'z', 'l', 'd', 'r', 'c', 'm'} a和b的交集: {'a', 'c'} a和b中不同时存在的元: {'r', 'b', 'm', 'z', 'l', 'd'}
再议不可变对象
上面我们讲了,str是不变对象,而list是可变对象。
对于可变对象,比如list,对list进行操作,list内部的内容是会变化的,比如:
>>> a = ['c', 'b', 'a'] >>> a.sort() >>> a ['a', 'b', 'c']
而对于不可变对象,比如str,对str进行操作呢:
>>> a = 'abc' >>> a.replace('a', 'A') 'Abc' >>> a 'abc'
虽然字符串有个replace()
方法,也确实变出了'Abc'
,但变量a
最后仍是'abc'
,应该怎么理解呢?
我们先把代码改成下面这样:
>>> a = 'abc' >>> b = a.replace('a', 'A') >>> b 'Abc' >>> a 'abc'
要始终牢记的是,a
是变量,而'abc'
才是字符串对象!有些时候,我们经常说,对象a
的内容是'abc'
,但其实是指,a
本身是一个变量,它指向的对象的内容才是'abc'
:
当我们调用a.replace('a', 'A')
时,实际上调用方法replace
是作用在字符串对象'abc'
上的,而这个方法虽然名字叫replace
,但却没有改变字符串'abc'
的内容。相反,replace
方法创建了一个新字符串'Abc'
并返回,如果我们用变量b
指向该新字符串,就容易理解了,变量a
仍指向原有的字符串'abc'
,但变量b
却指向新字符串'Abc'
了:
所以,对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。
小结
使用key-value存储结构的dict在Python中非常有用,选择不可变对象作为key很重要,最常用的key是字符串。
tuple虽然是不变对象,但试试把(1, 2, 3)
和(1, [2, 3])
放入dict或set中,并解释结果。
未经允许请勿转载:程序喵 » Python3 开发入门 —— 第八讲(dict字典、set集合)