Python3 开发入门 —— 第八讲(dict字典、set集合)

Python3 开发入门 —— 第一讲(输入、输出、代码注释)

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字典包含了以下内置函数:

序号函数及描述实例
1len(dict)
计算字典元素个数,即键的总数。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
>>> len(dict)
3
2str(dict)
输出字典,以可打印的字符串表示。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
>>> str(dict)
"{'Name': 'Runoob', 'Class': 'First', 'Age': 7}"
3type(variable)
返回输入的变量类型,如果变量是字典就返回字典类型。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
>>> type(dict)
<class 'dict'>

Python字典包含了以下内置方法:

序号函数及描述
1radiansdict.clear()
删除字典内所有元素 
2radiansdict.copy()
返回一个字典的浅复制
3radiansdict.fromkeys()
创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值
4radiansdict.get(key, default=None)
返回指定键的值,如果值不在字典中返回default值
5key in dict
如果键在字典dict里返回true,否则返回false
6radiansdict.items()
以列表返回可遍历的(键, 值) 元组数组
7radiansdict.keys()
以列表返回一个字典所有的键
8radiansdict.setdefault(key, default=None)
和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
9radiansdict.update(dict2)
把字典dict2的键/值对更新到dict里
10radiansdict.values()
以列表返回字典中的所有值
11pop(key[,default])
删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
12popitem()
随机返回并删除字典中的一对键和值。

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-to-str

当我们调用a.replace('a', 'A')时,实际上调用方法replace是作用在字符串对象'abc'上的,而这个方法虽然名字叫replace,但却没有改变字符串'abc'的内容。相反,replace方法创建了一个新字符串'Abc'并返回,如果我们用变量b指向该新字符串,就容易理解了,变量a仍指向原有的字符串'abc',但变量b却指向新字符串'Abc'了:

a-b-to-2-strs

所以,对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。

小结

使用key-value存储结构的dict在Python中非常有用,选择不可变对象作为key很重要,最常用的key是字符串。

tuple虽然是不变对象,但试试把(1, 2, 3)(1, [2, 3])放入dict或set中,并解释结果。


未经允许请勿转载:程序喵 » Python3 开发入门 —— 第八讲(dict字典、set集合)

点  赞 (1) 打  赏
分享到: