Python collection模块

​ collections模块主要实现了一些container datatypes(容器类型),作为builtin容器类型dict、list、set和tuple等的一个补充,包括以下新定义的容器类型:

类型 用途
namedtuple() factory function for creating tuple subclasses with named fields
deque 双端队列,支持两端快速出入队列操作
ChainMap 将多个mapping 对象组合成一个mapping对象
Counter dict subclass,用来计数hashable对象
OrderedDict dict subclass that remembers the order entries were added
defaultdict dict subclass,对dict中missing的key,调用一个指定的factory function
UserDict wrapper around dictionary objects for easier dict subclassing
UserList wrapper around list objects for easier list subclassing
UserString wrapper around string objects for easier string subclassing

chainMap

chainMap(*maps)用于连接多个mapping对象称为一个mapping,通常其速度快于使用字典的update方法连接。其构造方法为collections.ChainMap(*maps),当不传入参数时,ChainMap则会产生一个空dict;ChainMap底层用list存储mapping对象,并且可以通过.maps属性对mapping对象进行修改,对mapping对象的修改能够即时反应到ChainMap对象;查找会依次搜索每一个mapping对象,而修改、删除、新增只会在第一个mapping对象上进行操作。

​ ChainMap对象除了支持所有的mapping对象方法,还有以下几个特有的属性、方法:

  • maps

    如上所述,返回ChainMap所包装的mapping对象所组成的list,该list至少包含一个mapping对象;

  • new_child(m=None)

    创建child context,等价于ChainMap(m, *d.maps),当mNone时,等价于ChainMap({}, *d.maps)

  • parents

    返回parent context,即返回除了第一个mapping对象之外的所有mapping对象组成的ChainMap对象

    举个简单的例子:

    >>> baseline = {'music': 'bach', 'art': 'rembrandt'}                                                                
    >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}                                                            
    >>> from collections import ChainMap                                                                                
    >>> a = ChainMap(adjustments, baseline) 
    >>> a['art']                                                                                                        
    'van gogh'
    

Counter

Counter([iterable-or-mapping])类用于快速、方便的计数,使用频率很高的一个功能,它继承于dict,用于计数可哈希的对象,计数的数值可以是正整数、负整数和零,实例化方法有以下几种:

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

Counterdict不同之处在于如果Counter检索一个不存在的key时不会抛出KeyError,而是返回0:

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0
>>> del c['eggs']

​ 除了支持父类dict大部分的方法(不支持fromkeys(iterable)以及update([*iterable-or-mapping*])略有不同),还包括以下几个:

  • elements()

    返回一个iterator对象,每个元素重复其计数数值的次数(如果计数数值小于1,就忽略它)

    >>> c = Counter(a=4, b=2, c=-1, d=-2)
    >>> c.elements()
    >>> list(c.elements())  # If an element’s count is less than one, elements() will ignore it.
    
    <itertools.chain at 0x112f1be10>
    ['a', 'a', 'a', 'a', 'b', 'b']
    
  • most_common(n)

    返回计数最大的n个元素

    >>> c.most_common(2)
    c.most_common(2)
    
    >>> c.most_common()[:-3:-1] # c.most_common()[:-n-1:-1] n least common elements
    
  • subtract()

    执行计数减法操作,加法可以使用update()方法

    >>> c.subtract(Counter(a=1, b=2, c=3, d=4))
    >>> c
    >>> c.update({'a':3})  # update([iterable-or-mapping]), 添加式的update
    >>> c
    
    Counter({'a': 3, 'b': 0, 'c': -4, 'd': -6})
    Counter({'a': 6, 'b': 0, 'c': -4, 'd': -6})
    

    Counter还支持一些数学运算符,进行简便的运算:

    >>> c = Counter(a=-3, b=5, c=4)
    >>> d = Counter(a=-1, b=2, c=0)
    >>> c + d                       # add two counters together:  c[x] + d[x] (keeping only positive counts)
    Counter({'b': 7, 'c': 4})
    >>> c - d                       # subtract (keeping only positive counts)
    Counter({'b': 3, 'c': 4})
    >>> c & d                       # intersection:  min(c[x], d[x]) (keeping only positive counts)
    Counter({'b': 2})
    >>> c | d                       # union:  max(c[x], d[x]) (keeping only positive counts)
    Counter({'b': 5, 'c': 4})
    
    # 特殊的是,还提供两个shortcuts来表示空的Counter()加上或减去Counter对象
    >>> c = Counter(a=2, b=-4)
    >>> +c  # 相当于 Counter() + c
    Counter({'a': 2})
    >>> -c  # 相当于 Counter() - c
    Counter({'b': 4})
    

deque

collections.deque([iterable[, maxlen]]),以一个iterable对象作为参数进行初始化,得到一个双端队列。双端队列支持从任一侧线程安全,内存高效的appendpop操作,并且复杂度为时间O(1)。如果未指定maxlen或为None,则双端队列的长度可以增长到任意大小;反之,双端队列会限制为指定的最大长度。一旦限定长度的双端队列达到最大长度时,若再插入新的item,则队列另一端会自动丢弃相应数量的item。

  • 方法和属性

    • append(x)、appendleft(x) 插入元素,前者插到队列右边,后者插入到左边
    • extend(iterable)、extendleft(iterable) 插入多个元素,前者插到队列右边,后者插入到左边
    • pop()、popleft() 去除并返回最左(右)边的元素
    • clear() 清空队列
    • copy() 队列浅拷贝(同copy.copy(d)),深拷贝使用copy.deepcopy(d)
    • count(x) 计数队列中与x大小相等的元素个数
    • index(x[, start[, stop]]) 在[start, stop)范围内查找与x相等的第一个元素的index,如果没找到抛出ValueErrorc错误
    • insert(i, x) 在位置i插入x,若i位置超出队列指定的最大长度,引发IndexError
    • remove(value) 去除第一个与value相等的元素,若不存在引发ValueError
    • reverse() in place的反转队列元素
    • rotate(n=1) n> 0, 队列向右移n步,反之向左移
    • maxlen,这是一个只读属性

    除了以上的属性方法, deques 还支持iteration, pickling, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), in 操作符 以及索引操作,如d[-1]. 索引队列两边的元素复杂度都是O(1),当索引获取中间的元素复杂度会是O(n), 因此涉及大量中间元素索引操作的场景应该使用list。

  • 应用举例

    比如获取一个文件的后N行可以采用以下方式:

    def tail(filename, n=10):
        with open(filename) as f:
            return deque(f, n)
    

defaultdict

​ 关于defaultdict,我们可以先看一下dict中一个类似功能的函数setdefault(k, d=None):

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

for k, v in s:
    d.setdefault(k, []).append(v)

sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

​ 在上述代码中,setdefault(k, d=[])一句话相当于做了两件事情:一是获取key为k的的value,二是若该key不存在则设置其值为[]。即,d.get(k, [])以及如果key不存在就设置d[k] = []。现在再回到defaultdictdefaultdict([default_factory[, ...]]),构造方法中default_factory默认是Nonedefaultdictdict的一个subclass,它重写了一个__miss__方法以及拥有一个default_factory属性。

  • __miss__(key)

    • 该方法在当key不存在时才会且仅被__getitem__()调用,所以当使用dict.get()方法获取一个不存在的键值时,返回结果为None,而不是使用default_factory

    • default_factoryNone时,索引一个不存在的key会引发KeyError异常;

    • default_factory不为None时,索引一个不存在的key则使用default_factory进行初始化并返回值

      >>> from collections import defaultdict
      
      >>> d2 = defaultdict(int ,a=1, b=2)
      >>> d2['c']
      0
      
      >>> d2 = defaultdict(int ,a=1, b=2)
      >>> d2.get('c')
      None
      >>> d2
      defaultdict(int, {'a': 1, 'b': 2})
      
      >>> d1 = defaultdict(a=1, b=2)
      >>> d1['c']
      KeyError: 'c'
      
  • default_factory

    该属性在上述__miss__()函数中使用,由构造函数中的default_factory初始化,默认为None

    ​ 因此,上述例子可以使用defaultdict来实现如下:

    s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
    d = defaultdict(list)
    for k, v in s:
        d[k].append(v)
    
    sorted(d.items())
    [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
    

namedtuple

namedtuple用来构造带字段名的元组namedtuple的实例和普通元组消耗的内存一样多,因为字段名都被存在对应的类里面。这个类跟普通的对象实例比起来也要小一些,因为 Python 不会用 __dict__ 来存放这些实例的属性。它们可以在使用常规tuple的任何地方使用,并且它们还具有按名称(tuple只能按index)访问字段的能力。其构造函数为:collections.namedtuple(typename, field_names,*, rename=False, defaults=None, module=None),简单例子如下:

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

OrderedDict

OrderedDict和一般的dict类似,但是还具有记忆字典中存储的key的插入顺序。但是现在OrderDict可能用处不大了,因为从Python 3.7开始,一般的dict也具有这个特性。但是,dictOrderedDict依旧有些区别:

  • 对于常规dict,最重要的高效的mapping operations,而Track 插入顺序是次要的;
  • 对于OrderedDict,最重要的是排序操作,而空间效率、迭代效率以及更新字典的性能是次要的;
  • OrderedDict可以处理频繁的需要重排的操作,适合于Track最近的操作;
  • 判断两个OrderedDict是否相等同时要求顺序也相同;
  • OrderedDictpopitem(last=True)中可以通过last参数控制pop哪一端的元素;
  • OrderedDictmove_to_end(key, last=True)可以高效的将元素移至末尾;
  • 直到Python3.8,dict没有__reversed__()方法;

UserDict & UserList & UserString

UserDict & UserList & UserString分别是dictliststr的一个wrapper,在实际应用中,已经很少使用到它们了,因为我们可以直接方便的继承它们,自定义对应的子类,稍微了解一下即可,下面给出一个简单的例子:

你可能感兴趣的:(Python)