Python:映像、集合
一、字典
字典(dictionary)是Python中唯一的“映射”类型,映射这个概念在高中就学过:一个函数f将键(key, 定义域)映射到值(value, 值域)。这样的函数在字典中可以称为哈希(HASH)函数。通过哈希函数可以对键通过计算快速得到值的位置,而避免了线性搜索,极大的提高了数据值的存取效率;此外,字典是容器类型,可更新模型。基于这些特性,字典通常被认为是Python中最强大的数据类型之一。
1.创建和赋值
|
1
2
3
4
5
6
7
8
9
10
|
dict1 = {} #use curly slice to pack elements #here create an empty dict dict2 = {'name': 'earth', 'port': 80} #a dict with two key-value pairs dict3 = dict((['x', 1], ['y', 2])) #factory fun dict4 = {}.fromkeys(('x', 'y'), -1) #builtin fun fromkeys(), all valued -1 dict5 = {}.fromkeys(('x', 'y')) #all valued default 'None' |
fromkeys()可以使用一个可迭代的序列作为键集合创建一个默认字典,第二个参数是默认值,如果忽略的话所哟value默认为‘None
2.访问
|
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> dict1 = {'name': 'earth', 'port': 80} >>> dict1 #visit dict itself {'name': 'earth', 'port': 80} >>> dict1['name'] #visit single key-value 'earth'>>> for key in dict1.keys(): #use for loop to visit print "key=%s, value=%s" % (key, dict1[key]) key=name, value=earth key=port, value=80>>> |
如果你试图访问的键在字典中不存在,则会引发一个异常:
|
1
2
3
4
5
6
|
>>> dict1['age'] #key 'age' is not existed! Traceback (most recent call last): File "<pyshell#8>", line 1, in <module> dict1['age'] KeyError: 'age' |
所以之前,你最好先判断一下这个键是否存在:
|
1
2
3
4
|
if 'age' in dict1.keys(): ... else: ... |
3.更新
|
1
2
3
4
5
6
7
|
dict1['name'] = 'moon' #update existed item dict1['port'] = 777 #update existed item dict1['age'] = 20 #add a new item!! dict1.update(another_dict) #update a dict with another #update() is a builtin method of #dict class |
很简单吧?——如果键已存在,则用新值更新旧值,否则,加入新键值对。
4.删除
|
1
2
3
4
|
del dict1['name'] #删除“键”为“name”的条目 dict1.clear() #删除dict1中的所有条目 del dict1 #删除dict1这个字典 dict1.pop('name') #删除并返回“键”为‘name’的条目 |
二、映射类型操作符,内建函数,工厂函数,内建方法
1.标准类型操作符
=, <, <=, >, >=, ==, !=
字典相互比较的过程和列表、元组一样,都是一对一的比较,直至分出胜负,但不得不说,这里的比较要稍微复杂些,一会会讲到。
2.映射类型操作符
键查找操作符"[ ]"
注意,对于序列类来说,中括号中放置的是索引&下标(index),而对于映射类型,放置在中括号中的是键,或者说是参数,这和索引是不同的,不仅仅是概念上的差异,这涉及到寻址的方式,这里不会详细探讨这些。
成员关系操作符(in, not in)
3.内建函数
type()用于字典会返回其类型:“<type 'dict'>”
str()工厂方法用于字典会返回其字符串表示
cmp()用于字典的比较,算法为:先比较字典大小,elseif键,elseif值,但不得不说,用cmp做字典比较一般不是很有用
len():返回字典键值对的数目
hash():返回一个对象的hash值,它并不是作用于字典,而是作用于其它对象类型,一个可hash的对象可以作为字典的键,这个在后面会讲到的
sorted():作用于字典,可以返回一个对keys排序后的列表,这会经常用得到,但一定要明白的,字典中的键值对本身是无序的,这是和序列类型的一个本质区别
4.工厂函数
dict()作为字典的工厂函数是用来创建字典的,如果参数为空,则创建一个空字典‘{ }’,dict()的参数使用很灵活:
|
1
2
3
4
5
6
|
>>> dict(zip(('x', 'y'), (1, 2))) {'y': 2, 'x': 1} >>> dict([['x', 1], ['y', 2]]) {'y': 2, 'x': 1} >>> dict(x=1, y=2) {'y': 2, 'x': 1} |
|
1
2
3
4
|
dict1 = {'name': 'earth', 'age': 30} dict2 = dict(dict1) #浅拷贝 dict3 = dict.copy() #浅拷贝,使用内建方法 #第二种方法速度更快!! |
5.映射类型的内建方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
print '''映射类型内建方法 dict.clear() 删除字典中的所有元素,并返回一个浅拷贝的副本 dict.fromkeys(seq, val=None) 以序列seq中的元素作为键,创建并返回一个新字典 val为键值对的默认value dict.get(key, default=None) 对字典中的key,返回value,若key不存在,返回default dict.has_key(key) 判断字典中key是否存在 dict.items() 返回一个包含字典中键值对元组的列表 dict.keys() 返回字典中键的列表 dict.pop(key, [default])和方法get相似,区别在于不仅返回,还要删除 dict.setdefault(key, default=None) dict.update(dict2) dict.values() 返回包含所有value的列表 ''' |
对于不同的数据类型,讲到越往后就越粗糙了,因为很多内容有太多的相似性,你到现在应该可以熟练使用帮助文档了,所以不太清楚的时候多查查文档,这是一个好习惯:
dir(module_name), dir(type), help(module_name || type), module.__doc__ .......
三、字典的键
字典中的值可以是任何Python对象,甚至是字典以及用户自定义类型,但对于键却是有一些限制的。
1.不允许一个键对应多个值
你高中数学没有不及格的话,这个应该清楚的,这是严格的“映射”概念中所要求的。
|
1
|
dict1 = {'name': 'green', 'age': 20, 'name': 'marry'} |
上例中,出现了两个键‘name’,对于这种冲突,Python直接取最后的赋值,所以,最后得到的是:
|
1
2
|
>>>dict1 {'name': 'marry', 'age': 20} |
2.键必须是可哈希的
可哈希的对象才可以作为键,列表、字典这样的可变类型是不可哈希的,所以不能作为键。所有不可变类型都是可哈希的,所以可以作为字典的键。要说明的是,对于数字类型来说,值相等的数字表示相同的键,1,和1.0的哈希值是相同的,它们是相同的键。
对于可变对象,如果事先了__hash__()方法,方法返回一个整形,那它的hash值也是不变的,因此这类对象可以作为键,这是一种特例。
数字和字符串毫无疑问可以作为键,那么元组呢?(也是不可变类型)。在前面深拷贝和浅拷贝的例子中,我们可以看到,元组并不一定是一成不变的,如果其中某个成员是列表、字典等可变类型,我们仍然可以“改变元组”:
|
1
2
|
tuple_demo = (12, ['a', 'b']) tuple_demo[1][0] = 'name' |
所以,我们规定,元组中只包括数字、字符串这样的不可变参数,才可以作为字典中的有效键。
前面提到过hash()函数,使用hash(obj),可以返回对象的hash值,如果返回异常,说明这个对象不能够被hash,你应该明白:它一定不能用作字典的键。
下面的这个例子用于为字典的学习做一个小结:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#!/usr/bin/env python 'userpw.py --管理用于登陆系统的用户信息' db= {} #empty dict, used to record info~ of users def newuser(): prompt = 'login desired:' while True: #get a lawful username not existed name = raw_input(prompt).strip() if db.has_key(name): prompt = 'name taken, try another:' continue else: break #get password pwd = raw_input('passwd: ') db[name] = pwd #add item into dict def olduser(): name = raw_input('login: ') pwd = raw_input('passwd: ') passwd = db.get(name) #passwd is real pwd in db if passwd == pwd: print 'welcome back', name else: print 'login incorrect' def showmenu(): prompt =''' (N)ew User Login (E)xisting User Login (Q)uit Enter Choice: ''' return prompt #main loop start done = False #flag varible used to sign quit state while not done: chosen = False while not chosen: try: choice = raw_input(showmenu()n).strip()[0].lower() except (EOFError, KeyboardInterrupt): choice = 'q' print '\nYou picked: [%s]' % choice if choice not in 'neq': print 'invalid option, try again' else: chosen = True if choice == 'q': done = True #sign the flag if choice == 'n': newuser() if choice == 'e': olduser() if __name__ == '__main__': showmenu() |
四、集合
集合在现今的主流Python版本中已经是基本数据类型,过去是通过其它类模块(ImmutableSet,Set)实现的。这里的“集合”概念和数学中是相同的,你可以对其进行交、并、差、补等一些列操作。
Python中的集合有两种类型,可变集合(set)和不可变集合(frozenset),对于可变集合,可以添加和删减元素,但不可哈希,因此不能用作字典的key,也不能作为其它集合的元素;而不可变集合可以哈希,可以被用作key或者集合成员。
1.创建集合和赋值
|
1
2
3
4
5
6
7
8
|
#以下用三种方式创建了三个相同的可变集合 set1 = set('abcde') set2 = set(('a', 'b', 'c', 'd', 'e')) set3 = set(['a', 'b', 'c', 'd', 'e']) #以下用三种方式创建了三个相同的不可变集合 set4 = frozenset('abcde') set5 = frozenset(('a', 'b', 'c', 'd', 'e')) set6 = frozenset(['a', 'b', 'c', 'd', 'e']) |
2.访问集合成员
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> myset = set(['apple', 'pear', 'grape', 'banana']) >>> 'apple' in myset True>>> 'orange' in myset False>>> for fruit in myset: print fruit grape pear apple banana |
3.更新集合
只有可变集合(set)支持更新!
|
1
2
3
4
5
6
7
8
9
10
11
|
>>> myset.add('orange') #使用add增加元素 >>> myset set(['orange', 'grape', 'pear', 'apple', 'banana']) >>> myset.remove('pear') #使用remov删除元素 >>> myset set(['orange', 'grape', 'apple', 'banana']) >>> newfruit = set(('coco', 'watermelon')) >>> myset.update(newfruit) #update使用集合更新集合 >>> myset set(['coco', 'grape', 'apple', 'orange', 'watermelon', 'banana']) >>> del newfruit #删除集合 |
五、集合类型操作符和内建函数,内建方法
1.标准类型操作符
成员关系判定
in, not in
集合等价/不等价
== !=
子集/超集判定(<, <=, >, >=)
|
1
2
3
4
|
>>> set('book') <= set('bookshop') True>>> set('supermarket') >= set('market') True |
2.集合类型操作符(用于可变集合和不可变集合)
|
1
2
3
4
5
6
7
8
9
10
|
>>> s = set('abcde') >>> t = set('defgh') >>> s | t #联合操作,或称OR操作,也就是算并集 set(['a', 'c', 'b', 'e', 'd', 'g', 'f', 'h']) >>> s & t #求交集操作,或称AND操纵 set(['e', 'd']) >>> s - t #求差集/相对补集 set(['a', 'c', 'b']) >>> s ^ t #对称差分,类似C中亦或操作XOR set(['a', 'c', 'b', 'g', 'f', 'h']) |
3.集合类型操作符(用于可变集合)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
>>> s = set((1, 3, 5, 7)) >>> t = set((5, 7, 9, 0)) >>> s |= t >>> s set([0, 1, 3, 5, 7, 9]) >>> s &= t >>> s set([0, 9, 5, 7]) >>> s -= t >>> s set([]) >>> s ^= t >>> s set([0, 9, 5, 7]) |
这里很好理解,因为是可变集合,所以可以将上一部分讲的集合类型操作符以算数自反赋值的方式应用到集合上,当然,对不frozenset来说是不行的。
4.内建函数和工厂函数
len()是内建函数,可以计算集合大小,即集合中元素的个数。
set()是可变集合的工厂函数,用来生产可变集合,用法见“集合的创建和赋值”
frozenset()是不可变集合的工厂函数,用法和set()相同,见“集合的创建和赋值”
5.集合类型的内建方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#用于所有集合的方法 s.issubset(t) #如果s是t的子集,返回True s.issuperset(t) #如果s是t的超级,返回True s.union(t) #返回一个新集合(s和t的并集) s.intersection(t) #返回一个新集合(s和t的交集) s.difference(t) #返回一个新集合(s - t) s.symmetric_difference(t) #返回一个新集合(s ^ t) s.copy() #返回一个新集合,它是s的浅复制 #仅用于可变集合的方法 s.update(t) #用t中的元素更新s s.intersection_update(t)#将t中的元素并入到s中 s.difference_update(t) #s中现在是s和t的交际 s.symmetric_difference_update(t) #s中现在是(s - t) s.add(obj) #在s中添加对象obj s.remove(obj) #从s中删除对象obj,如果不存在则引发KeyError异常 s.discard(obj) #如果obj是s的元素,就从s中删除 s.pop() #删除s中任意一个对象,并返回 s.clear() #删除集合s中的所有元素 |
六、小结
至此,我们已经学完了Python所有的基本内建类型:数字,字符串,列表,元组,映射,集合。这些数据类型功能强大,使用简单,能够熟练使用它们是后续学习的关键。
参考博客:http://greenlcat.diandian.com/post/2012-10-10/40039924285

浙公网安备 33010602011771号