Python核心编程--学习笔记--7--字典和集合
本章介绍Python语言中的映射类型(字典)和集合类型,包括操作符、工厂函数、内建函数与方法。
1 字典
字典是Python中唯一的映射类型——键key直接映射到值value。字典是容器类型,其对象是可变的。字典中的数据是无序排列的。是哈希表。
创建字典——直接赋值{}、工厂函数dict()、内建方法fromkeys():
>>> dict1={}
>>> dict2={'name':'earth','port':80}
>>> dict1, dict2
({}, {'name': 'earth', 'port': 80})
>>> dict3=dict(['ab','cd'])
>>> dict3
{'a': 'b', 'c': 'd'}
>>> dict4={}.fromkeys(['ab','cd']) #对应同一值,默认对应None
>>> dict5={}.fromkeys(('ab','cd'), -1)
>>> dict4,dict5
({'ab': None, 'cd': None}, {'ab': -1, 'cd': -1})
访问字典元素——dict[key]、dict.method():
>>> d={'a':1, 'b':2, 'c':3}
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> d['b'] #直接通过dict[key]访问值
2
>>> d['d'] #如果key不存在则报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'd'
>>> 'a' in d #判断dict中是否有key
True
>>> d.has_key('c') #用方法来判断是否有key,不再推荐使用
True
>>> d.values(), d.keys(), d.items() #dict方法,分别返回 键、值、键值对 组成的无序列表
([1, 3, 2], ['a', 'c', 'b'], [('a', 1), ('c', 3), ('b', 2)])
>>> for key in d: #直接用迭代器访问字典,迭代的是字典的键
... print key
...
a
c
b
>>> print '%(a)d %(b)d %(c)d' % d #字典简化了print的格式化符
1 2 3
添加新元素/修改已存在元素——dict[key]=new_value:
>>> d['d'] = 4 #不存在的键,则添加键值对
>>> d['a'] = -1 #存在的键,则覆盖原来的值
>>> d
{'a': -1, 'c': 3, 'b': 2, 'd': 4}
删除字典元素和字典:
1 del dict[key] #删除键为“name”的条目
2 dict.clear() #删除dict中所有的条目,成为空字典
3 del dict #删除整个dict字典
4 dict.pop(key) #删除并返回键为key的条目
2 字典操作符
2.1 标准类型操作符
比较运算符、逻辑运算符 同样适用于字典。
比较字典大小不常用,算法流程为:①比较长度,长度大的字典大。②长度一样时,比较键,键比较顺序和keys()方法返回的顺序一样。(相同的键会映射到哈希表的同一位置,保证了这一过程的一致性) ③键一样时,按照键的顺序比较相应的值。④之前的比较都一样,则两个字典相同。
2.2 字典操作符
键查找操作符[]、键成员操作符[not] in。
3 字典相关的内建函数和工厂函数
3.1 标准类型函数
type()、str()、cmp()、len() 同样适用于字典。cmp()的比较过程见2.1。
3.2 字典相关的函数
dict()——参数可以是 空/可迭代的/另一个字典:
>>> dict() #生成空字典
{}
>>> dict( zip(('x', 'y'), (1, 2)) ) #参数为一个列表,即一个可迭代对象,其中每个可迭代的元素必须成对出现
{'y': 2, 'x': 1}
>>> dict({'x':1}) #参数为另一个字典,即浅拷贝,效率不高,不要使用这种方法
{'x': 1}
>>> {'x':1}.copy() #高效率的浅拷贝
{'x': 1}
>>> dict(ab=1,cd=2) #关键字参数
{'ab': 1, 'cd': 2}
hash(obj)——返回对象的哈希值,可用于判断是否能作为字典的键。如果不可哈希则产生TypeError错误。
4 字典的内建方法
1 dict.clear() #删除字典中所有元素
2 dict.copy() #返回字典(浅拷贝)的一个副本
3 dict.fromkeys(seq, val=None) #创建并返回一个新字典,以seq中的元素为键,val为所有键对应的初始值(默认为None)
4 dict.get(key, default=None) #读取key对应的值,如果不存在此键,则返回default的值(默认值为None)。
5 dict.has_key(key) #如果键存在,返回True。推荐使用成员操作符。
6 dict.items() #返回一个包含字典中(键, 值)对元组的列表
7 dict.iter*() #方法iteritems(),iterkeys(),itervalues(),返回一个迭代子而非列表,当元素很多时可以节省内存。
8 dict.keys() #返回一个包含字典中键的列表
9 dict.pop(key[, default]) #如果键存在,删除键值对并返回值;如果key键不存在,且没有指定default,则引发KeyError异常
10 dict.popitem() #删除并返回第一个键值对,如果字典为空则产生错误。
11 dict.setdefault(key, default=None) #如果不存在key键,由dict[key]=default为它赋值并返回值;存在则直接返回值
12 dict.update(dict2) #将字典dict2的键-值对添加到字典dict,重复的键则覆盖dict中原值
13 dict.values() #返回一个包含字典中所有值的列表
5 字典的键
一个键只能对应一个值。
键必须是可哈希的,不可变类型——字符串、数字、只包含不可变类型的元组——都是可哈希的。值相同的数字哈希值也相同hash(1) == hash(1.0)。
实现了__hash__()特殊方法的类,如果该方法返回一个不可变类型,也是可哈希的。因为解释器调用哈希函数,根据字典中键的值来计算数据存储的位置。
6 集合类型
集合对象是一组无序列的可哈希的值,集合成员可以用作字典的键。分为可变集合和不可变集合,可变集合不可哈希。
集合:支持[not] in检查成员、len()得到元素个数、for迭代集合成员。不支持索引、切片,没有键的概念。
Python中的集合和数学上的集合差不多,操作符如下:
1 数学符号 Python符号 说明
2 ∈ in 是集合成员
3 ∉ not in 不是集合成员
4 = == 等于
5 ≠ != 不等于
6 ⊂ < 真子集
7 ⊆ <= 子集
8 ⊃ > 严格超集
9 ⊇ >= 超集
10 ∩ & 交集
11 ∪ | 并集
12 - - 差补
13 △ ^ 对称差(A^B = A|B - A&B)
创建结合类型——只能用工厂函数set()和frozenset():
>>> s=set('abc') #可变集合,传入一个序列或者可迭代的对象。
>>> fs=frozenset([1,2,3]) #不可变集合
>>> s
set(['a', 'c', 'b'])
>>> fs
frozenset([1, 2, 3])
访问集合成员——检查成员、遍历成员:
>>> 'c' in s #检查成员
True
>>> for i in fs: #遍历成员
... print i
...
1
2
3
更新集合——使用集合内建的方法和操作符,只能对可变集合,进行添加或删除元素(具体见第8节的内建函数):
>>> s.add(321) #可变集合添加元素
>>> s
set(['a', 321, 'c', 'b'])
>>> fs.remove(1) #不可变集合删除元素,错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'frozenset' object has no attribute 'remove'
删除集合——del set即可。
7 集合类型操作符
7.1 标准类型操作符
成员操作符—— in、not in
集合等价—— ==、!=(两个集合的成员完全相同时,集合相同,不区分可变与不可变类型)
子集/超集—— 真子集<、子集<=、真超集>、超集>=
7.2 集合类型操作符
适用于所有集合——并集|、交集&、差补-、对称差^,返回一个新集合,参与运算的集合不变:
>>> s1=set([1,2])
>>> s2=set([2,3])
>>> fs=frozenset([2,3])
>>> s1, s2, fs
(set([1, 2]), set([2, 3]), frozenset([2, 3]))
>>> s1|s2, s1.union(s2) #s1和s2的交集,分别使用符号和方法
(set([1, 2, 3]), set([1, 2, 3]))
>>> s1&s2, s1.intersection(s2) #交集
(set([2]), set([2]))
>>> s1-s2, s1.difference(s2) #差补,即属于s1但是不属于s2的元素集合
(set([1]), set([1]))
>>> s1^s2, s1.symmetric_difference(s2) #对称差,即s1|s2 - s1&s2
(set([1, 3]), set([1, 3]))
>>> s1|fs, fs|s1 #可变与不可变类型集合运算,返回类型与左边的类型相同
(set([1, 2, 3]), frozenset([1, 2, 3]))
仅适用于可变集合——即集合运算的复合运算—— |=、&=、-=、^=,直接应用于左边的集合,没有返回值:
>>> s1 = set([1,2])
>>> s2 = set([1,2])
>>> s3 = set([2,3]) ###原始集合。以下运算都使用这三个数据,由于是在原集合上直接修改,每次运算都重新赋值,以下省略而已。
>>> s1 |= s3 #求并集并将新集合赋值给左值,没有返回值。分别使用 符号和方法。
>>> s2.update(s3)
>>> s1,s2
(set([1, 2, 3]), set([1, 2, 3]))
>>> s1 &= s3 #交集
>>> s2.intersection_update(s3)
>>> s1,s2
(set([2]), set([2]))
>>> s1 -= s3 #差补
>>> s2.difference_update(s3)
>>> s1,s2
(set([1]), set([1]))
>>> s1 ^= s3 #对称差
>>> s2.symmetric_difference_update(s3)
>>> s1,s2
(set([1, 3]), set([1, 3]))
8 内建函数
8.1 标准类型函数
len()——返回集合成员个数。
8.2 工厂函数
set()、frozenset()——生成一个集合。参数必须是可迭代的——序列、迭代器、支持迭代的对象(文件或字典)。
9 集合的内建方法
适用于所有集合的,之前也讲述过:
1 s.issubset(t) #符号<= 如果s是t的子集,则返回True
2 s.issuperset(t) #符号>= 如果t是s的超集,则返回True
3 s.union(t) #符号| 返回一个新集合,该集合是s和t的并集
4 s.intersection(t) #符号& 返回一个新集合,该集合是s和t的交集
5 s.isdisjoint(t) #如果s和t没有交集,则返回True
6 s.difference(t) #符号- 返回一个新集合,该集合成员是s的成员,但不是t的成员
7 s.symmetric_difference(t) #符号^ 返回一个新集合,该集合是s或t的成员,但不是s和t共有的成员
8 s.copy() #返回一个新集合,它是集合s的浅拷贝。比工厂函数快
仅适用于可变集合,有之前讲述的,也有一些新方法:
1 s.update(t) #符号|= s为s和t的并集 2 s.intersection_update(t) #符号&= s为s和t的交集 3 s.difference_update(t) #符号-= s中的成员是属于s但不包含在t中的元素 4 s.symmetric_difference_update(t) #符号^= s中的成员是属于s或t,但不属于s和t共有 5 s.add(obj) #在集合s中添加对象obj 6 s.remove(obj) #从集合s中删除对象obj,如果obj不存在,则引发KeyError错误 7 s.discard(obj) #从集合s中删除对象obj,如果obj不存在也不报错 8 s.pop() #删除集合s中的任意一个对象,并返回它 9 s.clear() #删除集合s中的所有元素
操作符和方法:当用操作符时,操作符两边的操作数必须是集合。在使用内建方法时,对象也可以是迭代类型的。
练习题
7-8 人力资源。创建一个简单的雇员姓名和编号的程序,让用户输入一组雇员姓名和编号,你的程序可以提供按照姓名排序输出的功能,雇员姓名显示在前面,后面是对应的雇员编号。附加题:添加一项功能,按照雇员编号的顺序输出数据。
1 #!/usr/bin/env Python 2 3 '''sorted by key or value''' 4 5 idx = 0 6 emp = {} 7 8 def mycmp(a, b): 9 if a[idx] > b[idx]: 10 return 1 11 elif a[idx] < b[idx]: 12 return -1 13 else: 14 return 0 15 16 while True: 17 info = raw_input('Enter like this: name:id ,q to quit: ') 18 if info == 'q': 19 break 20 else: 21 info = info.split(':') 22 emp[info[0]] = int(info[1]) 23 24 print sorted(emp.items(), mycmp) 25 idx = 1 26 print sorted(emp.items(), mycmp)
7–13 随机数。使用random模块中的randint()或randrange()方法生成一个随机数集合:从0到9(包括9)中随机选择,生成1到10个随机数。这些数字组成集合A(A可以是可变集合,也可以不是)。同理,按此方法生成集合B。每次新生成集合A和B后,显示结果A|B和A&B。
1 #!/usr/bin/env Python 2 3 import random 4 5 def make_list(): 6 new_list = [] 7 for i in range(random.randint(1, 10)): 8 new_list.append(random.randint(0, 9)) 9 return set(new_list) 10 11 A = make_list() 12 B = make_list() 13 print A, B 14 15 print A|B 16 print A&B