Python映射和集合

作者:最西瓜
来源:《Core Python Programming, Second Edition》CH7. Mapping and Set Types

字典

字典是无序的,Python 的字典内部通过哈希实现。通过 keys(), values() 和 items() 可以得到键、值、键值元组的列表。字典的工厂方法是 dict(),访问字典用 [key] 形式,字典不支持连接操作(+)和重复操作符(*)

字典通过 {} 形式创建,键值对用 key:value 形式保存,或者可以通过 fromkeys 创建,如下:

dict1 = {}
dict2 = {'name':'earth', 'port':80}
fdict = dict((['x',1], ['y', 2]))
ddict = {}.fromkeys(('x', 'y'), -1)
editc = {}.fromkeys(('foo', 'bar'))

字典本身是可迭代的,迭代的结果是一个个键。如果你需要有序遍历字典中的键可以用 for eachKey in sorted(dict2) ,如下:

for key in dict2:
    print 'key=%s, value=%s' % (key, dict2[key])

如果访问([])一个不存在的键将抛出 KeyError 错误,用 has_key() 或者 in 进行检查键是否存在。

对字典进行比较不是一个常用的操作,比较字典遵循如下原则:1.键值对多的较大 2.比较所有的键,比较顺序是 keys() 返回的顺序,任一键较大的较大 3.比较所有值,比较顺序与键一致,任一值较大的较大;

字典相关函数

dict() 函数用于创建一个字典,如果不传入参数则创建一个空字典,如果传入的是序列容器,则必须序列中的每个元素是成对出现的。如果参数是字典,则创建参数字典的拷贝。参数还可以是键值对。示例如下:

dict([['x', 1], ['y', 2]])
dict(x=1, y=2)

len() 函数用于返回字典的键值对数目。hash() 用于计算出对象的哈希值,如果对象是不可哈希的,将会抛出 TypeError 的错误。

hash([])   # TypeError: unhashable type: 'list'

字典对象方法

  • dict.clear() 清除掉字典中的所有元素;
  • dict.copy() 对字典进行浅拷贝并返回新的字典;
  • dict.fromkeys(seq, val=None) 将 seq 中的元素作为键,将 val 作为它们的初始值插入到字典中;
  • dict.get(key, default=None) 访问字典并得到与 key 关联的值,如果键不在字典中,返回默认值;
  • dict.has_key(key) 返回键是否在字典中,相当于 in
  • dict.items() 返回字典的 (key, value) 列表;
  • dict.keys() 返回字典的键的列表;
  • dict.values() 返回字典的值的列表;
  • dict.iteritems() dict.iterkeys() dict.itervalues() 返回以上对应的迭代器版本;
  • dict.viewitems() dict.viewkeys() dict.viewvalues() 返回以上对应的视图版本;
  • dict.pop(key [, default]) 从字典中删除并返回与 key 关联的值,如果不存在且没有传入 default 参数,则抛出 KeyError 错误;
  • dict.setdefault(key, default=None) 如果 key 不在字典中,设置 dict[key]=default
  • dict.update(dict2) 将 dict2 中键值对更新到 dict 中;

键的约束

字典中的键必须是不可变值,或者是实现了 __hash__() 的不可变对象,而且哈希值必须是整数。在字典中相同的整数和浮点数代表相同的键,整数 1 和浮点数 1.0 被认为是相同的键。如果元组作为键,必须是它里边的所有元素都是不可变的(如数字或者字符串)。

集合

集合是一组无序的可哈希值,这些值可以作为字典的键。集合支持 in 和 not in 操作符,支持 len() 函数和迭代,但没有索引和键。可变集合是 set 不可变集合是 frozenset,可变集合不能作为别的集合的元素或者作为字典的键,相反不可变集合是可以的。

常用的集合操作符:==(全等) !=(不全等) <(严格子集) <=(非严格子集) >(严格超集)>=(非严格超集)&(交集) |(并集) -(差集) ^(对称差集:项在集合中,但不会同时出现在二者中) 值得一提的是以上所有操作符可以混合可变集合和不可变集合作为操作数,同时跟元素加入集合的顺序无关。即: set('posh') == frozenset('shop') 为 True,对于别的返回的集合类型与左边的一致。

集合通过 set() 或者 frozenset() 来创建,其参数是元素迭代器。对于在 2.7 之后,可变集合还可以通过 {e1, e2, e3, …} 来创建,但是请记住 {} 表示创建空字典。

适用于所有集合的方法

  • s.issubset(t) 相当于 s <= t
  • s.issuperset(t) 相当于 s >= t
  • s.union(t) 相当于 s|t
  • s.intersection(t) 相当于 s&t
  • s.difference(t) 相当于 s-t
  • s.symmetric_difference(t) 相当于 s^t
  • s.copy() 返回一个浅拷贝集合

仅适用于可变集合的方法

  • s.update(t) 将 t 中的元素加入到 s 中;
  • s.intersection_update(t) s 仅保留 s&t 部分;
  • s.difference_update(t) s 仅保留 s-t 部分;
  • s.symmetric_difference_update(t) s 仅保留 s^t 部分;
  • s.add(obj) 加入元素 obj 到 s 中;
  • s.remove(obj) 从 s 中移除 obj,如果集合中没有元素 obj 抛出 KeyError 异常;
  • s.discard(obj) 从 s 中移除 obj,但不会抛出异常;
  • s.pop() 从集合中移除并返回一个元素;
  • s.clear() 清除集合的所有元素;

其中 obj 必须是可哈希的不可变对象,t 可以是任何可迭代的对象,如果用的是操作符则必须要求两边都是集合。这几个 update 方法,对于不可变集合可以用 &= , -= , ^= 实现,因为他们会创建新的对象。比较以下代码:

s = set('abc')
s & 'cbs'  #抛出异常
s.intersection('cbs')

u = frozenset('abc')
u.intersection_update('cbs') #抛出异常
u &= set('cbs')

Leave a Reply

Your email address will not be published. Required fields are marked *