python collections_Python 标准库之 collections (数据类型)

虽然 Python 提供了一些简单的数据结构类型,如 list 、 tuple 、 set 和 dict;这些数据类型可以满足我们日常使用,但 collections 就是为了代替这些标准数据类型而来。

快速查看表

collections 提供了 8 个 对象和 1 个工厂函数

对象

功能

deque

类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)

ChainMap

类似字典(dict)的容器类,将多个映射集合到一个视图里面

Counter

字典的子类,提供了可哈希对象的计数功能

OrderedDict

字典的子类,保存了他们被添加的顺序

UserDict

封装了字典对象,简化了字典子类化

UserList

封装了列表对象,简化了列表子类化

UserString

封装了列表对象,简化了字符串子类化

namedtuple()

创建命名元组子类的工厂函数

defaultdict

字典的子类,提供了一个工厂函数,为字典查询提供一个默认值

namedtuple()

语法:namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

namedtuple() 是一个工厂函数,它返回一个名为 typename 的元组类对象(元组的子类,因为它继承自tuple)

部分源码

result = type(typename, (tuple,), class_namespace)

field_names 是一个列表,表示这个类对象的字段名(参数名);

rename 表示无效参数名会自动转换成位置参数,转换格式为 “_” + 位置索引;

部分源码

if rename:

seen = set()

for index, name in enumerate(field_names):

if (not name.isidentifier()

or _iskeyword(name)

or name.startswith('_')

or name in seen):

field_names[index] = f'_{index}'

seen.add(name)

defaults 是为 field_names 提供默认值,其类型为一个可迭代对象。(注意:defaults 匹配最右边的参数,如参数 ['x', 'y', 'z'] 和默认值 (1, 2),y 默认值 1, z 默认值 2)

module 如果有值,会覆盖类对象的 __module__ 属性。

使用这个元组类对象来创建对象,可以通过字段名来获取属性值,也可以通过索引和迭代获取值。

官方提供的示例代码:

>>> Point = namedtuple('Point', ['x', 'y'])

>>> Point.__doc__ # 类对象的文档字符串

'Point(x, y)'

>>> p = Point(11, y=22) # 用位置参数或关键字实例化

>>> p[0] + p[1] # 像普通元组一样可索引

33

>>> x, y = p # 像普通的元组一样解包

>>> x, y

(11, 22)

>>> p.x + p.y # 按名称访问字段

33

>>> d = p._asdict() # 转换为字典

>>> d['x']

11

>>> Point(**d) # 从字典转换

Point(x=11, y=22)

>>> p._replace(x=100) # _replace() 类似于str.replace(),但以命名参数为目标

Point(x=100, y=22)

defaultdict

defaultdict 返回一个包含默认值的字典对象

defaultdict 接收一个参数 default_factory,它是 defaultdict 对象的一个属性;构造时,第一个参数为该属性提供初始值,默认为 None。

dict 在默认情况下是没有默认值的,当我们获取不存在的 key 时会引发 KeyError ,通过 setdefault 、 get 方法可以为获取不存在的 key 时设置默认值,但 defaultdict 能更简单高效的处理默认值的问题。

创建带有默认值的字典:

In [1]: from collections import defaultdict

In [2]: d = defaultdict(int, {'a': 1, 'b': 2})

In [3]: d['a']

Out[3]: 1

In [4]: d['b']

Out[4]: 2

In [5]: d['c']

Out[5]: 0

统计问题:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]

d = defaultdict(list)

for k, v in s:

d[k].append(v)

r = sorted(d.items())

print(r) # [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

deque (double-ended queue)

语法: deque([iterable[, maxlen]])

deque 是一个双端队列,它是具有队列和栈的性质的数据结构。

iterable 参数是一个可迭代对象,maxlen 用来限制队列的最大长度。

如果没有 deque 我们一般使用 list 作为队列和栈使用,使用 pop 弹出元素,使用 append 增加元素。

官方文档是这样表述的:

虽然 list 对象也支持类似操作,不过这里优化了定长操作和 pop(0) 和 insert(0, v) 的开销。它们引起 O(n) 内存移动的操作,改变底层数据表达的大小和位置。

deque 支持 list 所有操作并额外添加了以下内容:

appendleft(x)

添加 x 到左端。

extendleft(iterable)

扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

popleft()

移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。

rotate(n=1)

向右循环移动 n 步。 如果 n 是负数,就向左循环。

如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。

In [1]: from collections import deque

In [2]: d = deque('abcd')

In [3]: d

Out[3]: deque(['a', 'b', 'c', 'd'])

In [4]: d.popleft()

Out[4]: 'a'

In [5]: d.pop()

Out[5]: 'd'

In [6]: d.extendleft('efg')

In [7]: d

Out[7]: deque(['g', 'f', 'e', 'b', 'c'])

In [8]: d.rotate()

In [9]: d

Out[9]: deque(['c', 'g', 'f', 'e', 'b'])

In [10]: d.rotate(-1)

In [11]: d

Out[11]: deque(['g', 'f', 'e', 'b', 'c'])

ChainMap

官方文档解释:

一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多。

这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用。

一个ChainMap将多个dict(或其他映射)组合在一起。来创建一个单一的、可更新的视图。

In [1]: from collections import ChainMap

In [2]: cm = ChainMap({'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

In [3]: cm

Out[3]: ChainMap({'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

In [4]: list(cm)

Out[4]: ['c', 'b', 'a']

In [5]: cm['b']

Out[5]: 'B'

In [6]: cm['b'] = 'BBB'

In [7]: cm

Out[7]: ChainMap({'a': 'A', 'b': 'BBB'}, {'c': 'C', 'b': 'BB'})

In [8]: cm.maps

Out[8]: [{'a': 'A', 'b': 'BBB'}, {'c': 'C', 'b': 'BB'}]

基本的映射存储在一个列表中。 该列表可以使用maps属性进行访问或更新。

查找连续搜索底层映射,直到找到一个键。相反,写入、更新和删除只对第一个映射进行操作。

部分源码

def __getitem__(self, key):

for mapping in self.maps:

try:

return mapping[key] # can't use 'key in mapping' with defaultdict

except KeyError:

pass

return self.__missing__(key) # support subclasses that define __missing__

def __setitem__(self, key, value):

self.maps[0][key] = value

def __delitem__(self, key):

try:

del self.maps[0][key]

except KeyError:

raise KeyError('Key not found in the first mapping: {!r}'.format(key))

def pop(self, key, *args):

try:

return self.maps[0].pop(key, *args)

except KeyError:

raise KeyError('Key not found in the first mapping: {!r}'.format(key))

ChainMap 支持 dict 所有的方法;此外,ChainMap 还包含 一个可以更新的映射列表 maps ,上文提到过。还有 new_child ,它返回一个新的 ChainMap,它有一个参数 m ,如果 m 有内容,返回的 ChainMap 会在映射列表前加上 m;否则加上一个空字典。

In [1]: from collections import ChainMap

In [2]: cm = ChainMap({'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

In [3]: n_cm = cm.new_child()

In [4]: n_cm

Out[4]: ChainMap({}, {'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

In [5]: n_cm = cm.new_child({'e': 'E', 'f': 'F'})

In [6]: n_cm

Out[6]: ChainMap({'e': 'E', 'f': 'F'}, {'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

部分源码

def new_child(self, m=None):

if m is None:

m = {}

return self.__class__(m, *self.maps)

以及 parents ,它返回一个除了映射列表中第一个字典以外的所有字典的映射。

In [1]: from collections import ChainMap

In [2]: cm = ChainMap({'a': 'A', 'b': 'B'}, {'c': 'C', 'b': 'BB'})

In [3]: cm.parents

Out[3]: ChainMap({'c': 'C', 'b': 'BB'})

他与 ChainMap(*cm.maps[1:]) 相同。

部分源码

@property

def parents(self):

return self.__class__(*self.maps[1:])

Counter

Counter 是一个计数器,它接收的参数是可迭代对象或映射对象,当然也可以是 Counter 对象,只要是可哈希对象就可以被计数。 Counter 是 dict 的子类。

In [1]: from collections import Counter

In [2]: Counter('abcdaccd')

Out[2]: Counter({'a': 2, 'b': 1, 'c': 3, 'd': 2})

In [3]: Counter(['hey', 'hello', 'hey'])

Out[3]: Counter({'hey': 2, 'hello': 1})

Counter 支持字典的所有方法并且还提供了3个方法:

elements()

返回一个迭代器,每个元素重复的次数与它的计数次数相同。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于一,此元素则会被忽略。

In [1]: from collections import Counter

In [2]: c = Counter('abcdaccd')

In [3]: c.elements()

Out[3]:

In [4]: sorted(c.elements())

Out[4]: ['a', 'a', 'b', 'c', 'c', 'c', 'd', 'd']

most_common([n])

返回一个列表,列出 n 个最常见的元素和它们的数量,从最常见到最少。 如果 n 为 None,则列出所有元素的数量。计数值相等的元素按首次出现的顺序排序。

In [1]: from collections import Counter

In [2]: c = Counter('abcdaccd')

In [3]: c.most_common()

Out[3]: [('c', 3), ('a', 2), ('d', 2), ('b', 1)]

In [4]: c.most_common(2)

Out[4]: [('c', 3), ('a', 2)]

subtract([iterable-or-mapping])

从迭代对象或映射对象减去元素。和dict.update()一样,但是减去计数而不是替换它们。计数可以减到零以下。 输入和输出都允许包含0和负数。

In [1]: from collections import Counter

In [2]: c = Counter('abcdaccd')

In [3]: c

Out[3]: Counter({'a': 2, 'b': 1, 'c': 3, 'd': 2})

In [4]: c.subtract('cd')

In [5]: c

Out[5]: Counter({'a': 2, 'b': 1, 'c': 2, 'd': 1})

值得注意的是 fromkeys 并未实现,原因在源码是这样注释的:

对于计数器来说,没有等价的方法,因为在Counter.fromkeys('aaabbc', v=2)这样的情况下,语义会很模糊。

初始化计数器为零值没有必要,因为零已经是计数器查找的默认值。 使用Counter(set(iterable))可以很容易地将其初始化为1。 对于更奇特的情况,先用字典理解或dict.fromkeys()创建一个字典。

另外update 的工作方式与字典略有不同,像 dict.update() 一样,但是添加计数而不是替换它们。

update 参数可以是一个迭代,一个字典,或者另一个Counter实例。

关于 Counter 的骚操作:

位运算联合(|)是取任一 Counter 计数器的最大值。

位运算相交(&)是对应 Counter 计数的最小值。

计数器减法,但只保留正数的结果。

计数器加法,但只保留正数的结果。

...

In [1]: from collections import Counter

In [2]: c = Counter('abcdaccd')

In [3]: cc = Counter('abdd')

In [4]: cc & c

Out[4]: Counter({'a': 1, 'b': 1, 'd': 2})

In [5]: cc | c

Out[5]: Counter({'a': 2, 'b': 1, 'd': 2, 'c': 3})

In [6]: c - cc

Out[6]: Counter({'a': 1, 'c': 3})

In [7]: c + cc

Out[7]: Counter({'a': 3, 'b': 2, 'c': 3, 'd': 4})

OrderedDict

顾名思义,有顺序的字典。它是 dict 的子类,OrderedDict 插入时记录字典的顺序。

popitem(last=True)

从字典中删除并返回一个 (key,value) 键值对。如果 last 为 True,则按 LIFO 顺序返回键值对,如果 False 则按 FIFO 顺序返回键值对。

move_to_end(key, last=True)

将一个现有的元素 key 移动到末尾(如果 last 为 False,则移动到开头)。如果元素不存在,则引发KeyError。

OrderedDict 还可以通过 reversed() 来逆序迭代,迭代对象每次 yield OrderedDict 对象的 key。

In [1]: from collections import OrderedDict

In [2]: od = OrderedDict({'a': 'A', 'b': 'B', 'c': 'C'})

In [3]: od

Out[3]: OrderedDict([('a', 'A'), ('b', 'B'), ('c', 'C')])

In [4]: od.popitem()

Out[4]: ('c', 'C')

In [5]: od.move_to_end('a')

In [6]: od

Out[6]: OrderedDict([('b', 'B'), ('a', 'A')])

In [7]: r_od = reversed(od)

In [8]: r_od

Out[8]:

In [9]: list(r_od)

Out[9]: ['a', 'b']

额外的东西

一般使用以上数据类型已足以,但总有特殊清空下需要自定义类型,collections 提供了更容易处理的类,方便你基础它来构造自己的类型,而不是直接使用继承底层的数据结构。

UserDict

UserDict 类是用作字典对象的外包装。

UserList

这个类封装了列表对象。

UserString

UserString 类是用作字符串对象的外包装。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值