1.字典
字典通过键值对(key:value)的方式,把key映射到value,key必须是可hash的(hashable),由于python中所有内置的不可变类型(immutable)都是可以hash的,所以都可以用作字典的key,比如字符串(str)、数字(int,float)和只包含不可变类型元素的元组(tuple),如果元组直接或间接的包含了可变类型的元素,也不能作为字典的key,value则可以是任意类型。
字典中元素是无序的,并不会按照插入的顺序排序,可能会是任意的顺序,如果想要有序的字典,可以使用collections.OreredDict。但是从Python3.7开始,字典默认是按照插入顺序排序的了。
1.1字典的创建
创建一个字典可以通过以下3种方式:
- 大括号{}方式:
>>> d = {'name':'lili','age':18}
>>> d
{'name': 'lili', 'age': 18}
- dict关键字方式:
dict的定义如下:
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
根据定义dict接受如下形式的参数进行初始化:
>>> dict(one=1, two=2) # 关键字参数形式(**kwargs)
{'one': 1, 'two': 2}
>>> dict({'one':1, 'two':2}) # 字典形式(mapping)
{'one': 1, 'two': 2}
>>> dict([('one',1), ['two',2]]) # 可迭代类型中内嵌2个元素的可迭代类型(iterable)
{'one': 1, 'two': 2}
>>> dict({'one':1}, two=2) # 字典+关键字参数形式(mapping + **kwargs)
{'one': 1, 'two': 2}
>>> dict([('one',1)], two=2) # 可迭代类型+关键字参数形式(iterable + **kwargs)
{'one': 1, 'two': 2}
- 字典推导式(dict comprehension):
>>> {x: x**2 for x in (2,4,6)}
{2: 4, 4: 16, 6: 36}
1.2字典操作
- len(d)
返回字典d的长度,即包含多少个键值对
>>> d = {'one':1, 'two':2}
>>> len(d)
2
- d[key]
返回key对应的value,如果key不存在,则抛出KeyError异常
>>> d = {'one':1, 'two':2}
>>> d['one']
1
>>> d['three']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'three'
- d[key] = value
设置key对应的value,如果key不存在则自动添加
>>> d = {'one':1, 'two':2}
>>> d['two'] = 2.0
>>> d['three'] = 3
>>> d
{'one': 1, 'two': 2.0, 'three': 3}
- del d[key]
删除key对应的项,如果key不存在则抛出KeyError异常
>>> d = {'one':1, 'two':2}
>>> del d['two']
>>> d
{'one': 1}
- pop(key[,default])
删除key对应的项,并返回对应的value,如果key不存在并且传入了default参数,那么返回default,否则抛出KeyError异常
>>> d = {'one':1, 'two':2}
>>> d.pop('two')
2
>>> d.pop('three',0)
0
>>> d
{'one': 1}
- popitem()
任意删除并返回一个项,由于字典是无序的,所以删除的项是不确定的
>>> d = {'one':1, 'two':2}
>>> d.popitem()
('two', 2)
>>> d
{'one': 1}
从python3.7开始字典是有序的(按照插入顺序排序),所以popitem()会按照LIFO规则删除,即相当于删除最后一个项
- key in d
如果key存在于字典d中,则返回True,否则返回False
>>> d = {'one':1, 'two':2}
>>> 'one' in d
True
>>> 'three' in d
False
- key not in d
如果key不存在于字典d中,则返回True,否则返回False
>>> d = {'one':1, 'two':2}
>>> 'one' not in d
False
>>> 'three' not in d
True
- iter(d)
返回一个包含字典d的所有key的迭代器(iterator)
>>> d = {'one':1, 'two':2}
>>> for k in iter(d):
... print(k)
...
one
two
- clear()
清空字典
>>> d = {'one':1, 'two':2}
>>> d.clear()
>>> d
{}
- copy()
返回字典的浅拷贝
>>> d1 = {'one':1, 'two':2}
>>> d2 = d1.copy()
>>> d2
{'one': 1, 'two': 2}
- classmethod fromkeys(seq[, value])
返回一个新的字典,字典的keys来自参数seq,并且所有key的value为参数value,value参数默认值为None。
>>> dict.fromkeys(['three','four'])
{'three': None, 'four': None}
>>> dict.fromkeys(['three','four'],0)
{'three': 0, 'four': 0}
- get(key[, default])
返回key对应的value,如果key不存在则返回default,default默认为None
>>> d = {'one':1, 'two':2}
>>> d.get('one')
1
>>> d.get('three',0)
0
- items()
返回一个包含所有项的字典视图(view),每一项是2个元素的tuple。分别为key和value
>>> d = {'one':1, 'two':2}
>>> for k,v in d.items():
... print('%s = %s' % (k,v))
...
one = 1
two = 2
- keys()
返回一个包含所有key的字典视图
>>> d = {'one':1, 'two':2}
>>> for k in d.values():
... print(k)
...
one
two
- values()
返回一个包含所有value的字典视图
>>> d = {'one':1, 'two':2}
>>> for v in d.values():
... print(v)
...
1
2
- setdefault(key[, default])
如果key存在于字典中,则返回其对应的value,否则插入key,并且将其value设置为default,default默认为None
>>> d = {'one':1, 'two':2}
>>> d.setdefault('two')
2
>>> d.setdefault('three',3)
3
>>> d
{'one': 1, 'two': 2, 'three': 3}
- update([other])
更新字典中的项,可接受参数类型与dict关键字一样
>>> d = {'one':1, 'two':2}
>>> d.update({'two':2.0,'three':3}) # mapping形式
>>> d
{'one': 1, 'two': 2.0, 'three': 3}
>>> d.update([('three',3.0),('four',4)]) # iterable形式
>>> d
{'one': 1, 'two': 2.0, 'three': 3.0, 'four': 4}
>>> d.update(five=5,six=6) # **kwargs形式
>>> d
{'one': 1, 'two': 2.0, 'three': 3.0, 'four': 4, 'five': 5, 'six': 6}
>>> d.update({'six':6.0},seven=7) # mapping + **kwargs形式
>>> d
{'one': 1, 'two': 2.0, 'three': 3.0, 'four': 4, 'five': 5, 'six': 6.0, 'seven': 7}
>>> d.update([('one',1.0),('four',4.0)],five=5.0,seven=7.0) # iterable + **kwargs形式
>>> d
{'one': 1.0, 'two': 2.0, 'three': 3.0, 'four': 4.0, 'five': 5.0, 'six': 6.0, 'seven': 7.0}
1.3字典视图
上面提到的d.keys()、d.values()和d.items()等方法返回的都是一个视图类型(view object),通过这些视图可以访问字典d的keys、values或items,并且视图会随着字典的变化而自动更新。
>>> d = {'one':1, 'two':2}
>>> keys = d.keys()
>>> values = d.values()
>>> items = d.items()
>>> keys
dict_keys(['one', 'two'])
>>> values
dict_values([1, 2])
>>> items
dict_items([('one', 1), ('two', 2)])
# 视图随着字典变化而动态更新
>>> d.update(three=3)
>>> keys
dict_keys(['one', 'two', 'three'])
>>> values
dict_values([1, 2, 3])
>>> items
dict_items([('one', 1), ('two', 2), ('three', 3)])
>>>
>>> for k in keys:
... print(k)
...
one
two
three
1.4字典比较
字典只支持==比较操作符,仅当所有项都相等时才相等,对于<、>、<=、>=比较操作符都不支持,如果使用会抛TypeError错误。
2.集合
集合(set)是一些无序、无重复并且可hash元素的组合。通常用于是否包含某个成员的检测、去除重复元素等操作。同时也支持数学上的集合运算,比如交集、并集、差集和对称差集。
Python内置2中类型集合,set和frozenset,set是可变类型,frozenset是不可变类型。
2.1集合创建
集合创建可以通过以下2种方式:
- 大括号{}方式
>>> s = {'a','b','c','a'}
>>> s
{'a', 'b', 'c'} # 元素相等只能保留一个
- set或frozenset关键字方式
set和frozenset的定义如下:
class set([iterable])
class frozenset([iterable])
根据以上定义可以通过下面的方式创建集合:
>>> s = set(['a','b','c'])
>>> fs = frozenset(['a','b','c'])
>>> s
{'a', 'b', 'c'}
>>> fs
frozenset({'a', 'b', 'c'})
>>> s.add('d') # set是可变类型
>>> s
{'a', 'b', 'd', 'c'}
>>> fs.add('d') # frozenset是不可变类型
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'frozenset' object has no attribute 'add
- 集合推导式
>>> {x for x in range(1,11)}
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
集合中的元素必须是可以hash的:
# str、number和tuple类型都是可以hash的
>>> {'one',2,(3,4)}
{'one', 2, (3, 4)}
# list是不可hash(unhashable)类型
>>> {1,[2]}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
# 间接包含unhashable也不行
>>> {1,(2,[3])}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
如果要创建空集合,必须使用set或frozenset关键字,不能使用大括号,因为{}创建的是一个空字典。
>>> s = set()
>>> s
set()
>>> fs = frozenset()
>>> fs
frozenset()
>>> d = {}
>>> d
{}
>>> type(d)
<class 'dict'>
2.2集合操作
以下是set和frozenset都支持的操作:
- len(s)
返回结合中元素的个数
>>> s = {1,2}
>>> len(s)
2
- x in s
判断x是否被包含于集合s中
>>> s = {1,2}
>>> 1 in s
True
>>> 3 in s
False
- x not in s
判断x是否不被包含于集合s中
>>> s = {1,2}
>>> 1 not in s
False
>>> 3 not in s
True
- isdisjoint(other)
判断当前集合是否与其它集合other没有交集
>>> s = {1,2}
>>> s.isdisjoint({3,4})
True
>>> s.isdisjoint({2,3})
False
- issubset(other)
set <= other
判断当前集合是否为其它集合other的子集
子集:指一个集合中的所有元素都属于另一个集合
>>> s = {1,2}
>>> other = {1,2,3}
>>> s.issubset(other)
True
>>> s <= other
True
>>> other = {1,4,3}
>>> s.issubset(other)
False
>>> s <= other
False
- set < other
判断当前集合是否为其它集合other的真子集
真子集:指一个集合中的所有元素都属于另一个集合,但这两个集合并不完全相同
>>> {1,2} < {1,2,3}
True
>>> {1,2} < {1,2}
False
- issuperset(other)
set >= other
判断当前集合是否为其它集合other的超集。
如果一个集合S2中的每一个元素都在集合S1中,且集合S1中可能包含S2中没有的元素,则集合S1就是S2的一个超集,反过来,S2是S1的子集。
>>> s = {1,2,3}
>>> other = {1,2}
>>> s.issuperset(other)
True
>>> s >= other
True
- set > other
判断当前集合是否是其它集合other的真超集
S1是S2的超集,若S1中一定有S2中没有的元素,则S1是S2的真超集,反过来S2是S1的真子集。
>>> {1,2,3} > {1,2}
True
>>> {1,2} > {1,2}
False
- union(*others)
set | other | …
当前集合与其它一个或多个集合求并集
>>> s = {1,2}
>>> other = {2,3}
>>> s.union(other)
{1, 2, 3}
>>> s | other
{1, 2, 3}
- intersection(*others)
set & other & …
当前集合与其它一个或多个集合求交集
>>> s = {1,2}
>>> other = {2,3}
>>> s.intersection(other)
{2}
>>> s & other
{2}
- difference(*others)
set - other - …
当前集合与其它一个或多个集合求差集
>>> s = {1,2}
>>> other = {2,3}
>>> s.difference(other)
{1}
>>> s - other
{1}
- symmetric_difference(other)
set ^ other
当前集合与其它集合other求对称差集
>>> s = {1,2}
>>> other = {2,3}
>>> s ^ other
{1, 3}
>>> s.symmetric_difference(other)
{1, 3}
- copy()
返回当前集合的一个浅拷贝
>>> s = {1,2}
>>> s.copy()
{1, 2}
需要注意的是以上的比较方法union()、intersection()、difference()、symmetric_difference()、issubset()和issuperser(),接受的参数除了集合类型外,还可以是可迭代类型(iterable)。相比之下,对应的比较运算符只能接受集合类型参数。
>>> {1,2}.union([3,4]) # union方法可以接受iterable类型
{1, 2, 3, 4}
>>> {1,2} | [3,4] # | 运算符不能接受iterable类型
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
以下是只有set支持的操作:
- update(*others)
set |= other |= …
将当前集合与其它一个或多个集合求并集,然后更新到当前集合
>>> s = {1,2}
>>> other = {2,3}
>>> s.update(other)
>>> s
{1, 2, 3}
>>> s |= {3,4}
>>> s
{1, 2, 3, 4}
- intersection_update(*other)
set &= other &= …
将当前集合与其它一个或多个集合求交集,然后更新到当前集合
>>> s = {1,2}
>>> other = {2,3}
>>> s.intersection_update(other)
>>> s
{2}
>>> s &= {3,4}
>>> s
set()
- add(elem)
添加一个元素elem到当前集合
>>> s = {1,2}
>>> s.add(3)
>>> s
{1, 2, 3}
- remove(elem)
从当前集合删除元素elem,如果elem不存在则抛KeyError异常
>>> s = {1,2}
>>> s.remove(2)
>>> s
{1}
>>> s.remove(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 2
- discard(elem)
从当前集合删除元素elem,如果elem不存在也不抛异常
>>> s = {1,2}
>>> s.discard(2)
>>> s
{1}
>>> s.discard(2)
>>> s
{1}
- pop()
从当前集合任意删除一个元素并返回,由于集合是无序的,所以删除哪个元素不确定,如果当前集合为空,则抛KeyError异常
>>> s = {1,2}
>>> s.pop()
1
>>> s.pop()
2
>>> s.pop()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'pop from an empty set'
- clear()
清空当前集合
>>> s = {1,2}
>>> s.clear()
>>> s
set()
同样的以上的update()、intersection_update()和symmetric_difference_update()也可以接受可迭代类型参数,但对应的运算符只能接受集合类型参数。
3.immutable和hashable
Python中不可变类型immutable都是hashable类型的,但是hashable类型并不一定都是immutable的,因为默认所有自定义类的实例都是hashable类型的,其hash值通常就是id()函数的计算结果,由于用户自定义类型不一定是不可变类型,所以hashable类型不一定都是immutable类型的。