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)
4394891088set 集合
集合(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.rset可以看成数学意义上的无序和无重复元素的集合,因此,两个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集合)
程序喵