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-8 View Code

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
7-13 View Code 
posted @ 2013-12-01 14:59  阿杰的专栏  阅读(315)  评论(0编辑  收藏  举报