collections容器详解

collections --- 容器数据类型

这个模块实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。

namedtuple() 创建命名元组子类的工厂函数
deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter 字典的子类,提供了可哈希对象的计数功能
OrderedDict 字典的子类,保存了他们被添加的顺序
defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict 封装了字典对象,简化了字典子类化
UserList 封装了列表对象,简化了列表子类化
UserString 封装了列表对象,简化了字符串子类化

deque 对象

返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空。

Deque队列是由栈或者queue队列生成的(发音是 “deck”,”double-ended queue”的简称)。Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。

 

双向队列(deque)对象支持以下方法:

append(x)

添加 x 到右端。

appendleft(x)

添加 x 到左端。

clear()

移除所有元素,使其长度为0.

copy()

创建一份浅拷贝。

count(x)

计算deque中个数等于 x 的元素。

extend(iterable)

扩展deque的右侧,通过添加iterable参数中的元素。

extendleft(iterable)

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

index(x[, start[, stop]])

返回第 x 个元素(从 start 开始计算,在 stop 之前)。返回第一个匹配,如果没找到的话,升起ValueError 。

insert(ix)

在位置 i 插入 x 。

如果插入会导致一个限长deque超出长度 maxlen 的话,就升起一个 IndexError 。

pop()

移去并且返回一个元素,deque最右侧的那一个。如果没有元素的话,就升起 IndexError 索引错误。

popleft()

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

remove(value)

移去找到的第一个 value。 如果没有的话就升起 ValueError 。

reverse()

将deque逆序排列。返回 None 。

rotate(n=1)

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

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

Deque对象同样提供了一个只读属性:

maxlen

Deque的最大尺寸,如果没有限定的话就是 None 。

举例:

一个 轮询调度器 可以通过在 deque 中放入迭代器来实现。值从当前迭代器的位置0被取出并暂存(yield)。 如果这个迭代器消耗完毕,就用 popleft() 将其从对列中移去;否则,就通过 rotate() 将它移到队列的末尾

from collections import deque


def roundrobin():
    iterable = ['ABC', 'D', 'EF']
    iterators = deque(map(iter, iterable))
    while iterators:
        try:
            while True:
                yield next(iterators[0])
                iterators.rotate(-1)
        except Exception:
            iterators.popleft()
r = roundrobin()
for i in r:
    print(i)

defaultdict 对象

返回一个新的类似字典的对象。 defaultdict 是内置 dict 类的子类。它重载了一个方法并添加了一个可写的实例变量。其余的功能与 dict 类相同,此处不再重复说明。

defaultdict 对象除了支持 dict 的操作,还支持下面的方法作为扩展:

__missing__(key)

如果 default_factory 是 None , 它就升起一个 KeyError 并将 key 作为参数。

如果 default_factory 不为 None , 它就会会被调用,不带参数,为 key 提供一个默认值, 这个值和 key 作为一个对被插入到字典中,并返回。

如果调用 default_factory 升起了一个例外,这个例外就被扩散传递,不经过改变。

这个方法在查询键值失败时,会被 dict 中的 __getitem__() 调用。不管它是返回值或升起例外,都会被 __getitem__() 传递。

注意 __missing__() 不会 被 __getitem__() 以外的其他方法调用。意思就是 get() 会向正常的dict那样返回 None ,而不是使用 default_factory 。

defaultdict 支持以下实例变量:

default_factory

这个属性被 __missing__() 方法使用;它从构建器的第一个参数初始化,如果提供了的话,否则就是 None 。

 

使用 list 作为 default_factory ,很容易将序列作为键值对加入字典:

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

当每个键第一次遇见时,它还没有在字典里面;所以条目自动创建,通过 default_factory 方法,并返回一个空的 list 。 list.append() 操作添加值到这个新的列表里。当键再次被存取时,就正常操作, list.append() 添加另一个值到列表中

 

设置 default_factory 为 int ,使 defaultdict 在计数方面发挥好的作用:

s = "lianiisdhddishds"
d = defaultdict(int)
for k in s:
    d[k] += 1
print(d)

当一个字母首次遇到时,它就查询失败,所以 default_factory 调用 int() 来提供一个整数0作为默认值。自增操作然后建立对每个字母的计数。

函数 int() 总是返回0,是常数函数的特殊情况。一个更快和灵活的方法是使用lambda函数,可以提供任何常量值(不只是0):

def constant_factory(value):
    return lambda :value
d= defaultdict(constant_factory('miss'))
d.update(name="lian")
print('%(object)s' % d)

 

namedtuple() 命名元组的工厂函数

命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。

collections.namedtuple(typenamefield_names*rename=Falsedefaults=Nonemodule=None)

返回一个新的元组子类,名为 typename 。这个新的子类用于创建类元组的对象,可以通过域名来获取属性值,同样也可以通过索引和迭代获取值。子类实例同样有文档字符串(类名和域名)另外一个有用的 __repr__() 方法,以 name=value 格式列明了元组内容。

field_names 是一个像 [‘x’, ‘y’] 一样的字符串序列。另外 field_names 可以是一个纯字符串,用空白或逗号分隔开元素名,比如 'x y' 或者 'x, y' 。

任何有效的Python 标识符都可以作为域名,除了下划线开头的那些。有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,另外不能是关键词 keyword 比如 classforreturnglobalpass, 或 raise 。

如果 rename 为真, 无效域名会自动转换成位置名。比如 ['abc', 'def', 'ghi', 'abc'] 转换成 ['abc', '_1', 'ghi', '_3'] , 消除关键词 def 和重复域名 abc 。

defaults 可以为 None 或者是一个默认值的 iterable 。如果一个默认值域必须跟其他没有默认值的域在一起出现,defaults 就应用到最右边的参数。比如如果域名 ['x', 'y', 'z'] 和默认值 (1, 2) ,那么 x 就必须指定一个参数值 ,y 默认值 1 , z 默认值 2 。

如果 module 值有定义,命名元组的 __module__ 属性值就被设置。

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y','z'],defaults=(1,2))
p = Point(x=11)
print(p)
print(p[0], p[1])
print(p.x)
print(p.y)
print(p.z)

lassmethod somenamedtuple._make(iterable)

类方法从存在的序列或迭代实例创建一个新实例。

from collections import namedtuple

l = [1, 2, 3]
Point = namedtuple('Point', ['x', 'y', 'z'])
p = Point._make(l)
print(p)

somenamedtuple._asdict()

返回一个新的 dict ,它将字段名称映射到它们对应的值:

from collections import namedtuple

l = [1, 2, 3]
Point = namedtuple('Point', ['x', 'y', 'z'])
p = Point._make(l)
dic = p._asdict()
print(dic.get("x"))

somenamedtuple._replace(**kwargs)

返回一个新的命名元组实例,并将指定域替换为新的值

somenamedtuple._fields

字符串元组列出了域名。用于提醒和从现有元组创建一个新的命名元组类型。

somenamedtuple._field_defaults

默认值的字典。

要获取这个名字域的值,使用 getattr() 函数 

要将字典转换为命名元组,请使用 ** 运算符(如 解包参数列表 中所述)

因为一个命名元组是一个正常的Python类,它可以很容易的通过子类更改功能。这里是如何添加一个计算域和定宽输出打印格式:

from collections import namedtuple


class Point(namedtuple('Point', ['x', 'y'])):
    __slots__ = ()

    @property
    def hypot(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

    def __str__(self):
        return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)


for p in Point(3, 4), Point(5, 6):
    print(p)

上面的子类设置 __slots__ 为一个空元组。通过阻止创建实例字典保持了较低的内存开销。

OrderedDict 对象

有序词典就像常规词典一样,但有一些与排序操作相关的额外功能。由于内置的 dict 类获得了记住插入顺序的能力(在 Python 3.7 中保证了这种新行为),它们变得不那么重要了。

一些与 dict 的不同仍然存在:

  • 常规的 dict 被设计为非常擅长映射操作。 跟踪插入顺序是次要的。
  • OrderedDict 旨在擅长重新排序操作。 空间效率、迭代速度和更新操作的性能是次要的。
  • 算法上, OrderedDict 可以比 dict 更好地处理频繁的重新排序操作。 这使其适用于跟踪最近的访问(例如在 LRU cache 中)。
  • 对于 OrderedDict ,相等操作检查匹配顺序。
  • OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。
  • OrderedDict 类有一个 move_to_end() 方法,可以有效地将元素移动到任一端。
  • Python 3.8之前, dict 缺少 __reversed__() 方法。
  • class collections.OrderedDict([items])

    返回一个 dict 子类的实例,它具有专门用于重新排列字典顺序的方法。

  • popitem(last=True)

    有序字典的 popitem() 方法移除并返回一个 (key, value) 键值对。 如果 last 值为真,则按 LIFO 后进先出的顺序返回键值对,否则就按 FIFO 先进先出的顺序返回键值对。

    move_to_end(keylast=True)

    将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发 KeyError:

  • d =OrderedDict.fromkeys("abcd")
    d.move_to_end('b')
    for i in d:
        print(i)
    

    内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。 什么是LRU算法? LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的。

  • 这里使用OrderedDict实现LRU

  • from collections import OrderedDict
    
    
    class LRU(OrderedDict):
        def __init__(self, maxsize, *args, **kwargs):
            self.maxsize = maxsize
            super().__init__(*args, **kwargs)
    
        def __getitem__(self, key):
            value = super().__getitem__(key)
            self.move_to_end(key)
            return value
    
        def __setitem__(self, key, value):
            super().__setitem__(key, value)
            if len(self) > self.maxsize:
                oldest = next(iter(self))
                del self[oldest]
    

     

    ChainMap 对象

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

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

    class collections.ChainMap(*maps)

    一个 ChainMap 将多个字典或者其他映射组合在一起,创建一个单独的可更新的视图。 如果没有 maps 被指定,就提供一个默认的空字典,这样一个新链至少有一个映射。

    底层映射被存储在一个列表中。这个列表是公开的,可以通过 maps 属性存取和更新。没有其他的状态。

    搜索查询底层映射,直到一个键被找到。不同的是,写,更新和删除只操作第一个映射。

    一个 ChainMap 通过引用合并底层映射。 所以,如果一个底层映射更新了,这些更改会反映到 ChainMap 。

    支持所有常用字典方法。另外还有一个 maps 属性(attribute),一个创建子上下文的方法(method), 一个存取它们首个映射的属性(property):

    maps

    一个可以更新的映射列表。这个列表是按照第一次搜索到最后一次搜索的顺序组织的。它是仅有的存储状态,可以被修改。列表最少包含一个映射。

    new_child(m=None)

    返回一个新的 ChainMap 类,包含了一个新映射(map),后面跟随当前实例的全部映射(map)。如果 m被指定,它就成为不同新的实例,就是在所有映射前加上 m,如果没有指定,就加上一个空字典,这样的话一个 d.new_child() 调用等价于 ChainMap({}, *d.maps) 。这个方法用于创建子上下文,不改变任何父映射的值。

    在 3.4 版更改: 添加了 m 可选参数。

    parents

    属性返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。 使用的场景类似在 nested scopes 嵌套作用域中使用 nonlocal 关键词。用例也可以类比内建函数 super() 。一个 d.parents 的引用等价于 ChainMap(*d.maps[1:]) 。

    注意,一个 ChainMap() 的迭代顺序是通过扫描最后的映射来确定的:

  • >>> baseline = {'music': 'bach', 'art': 'rembrandt'}
    >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
    >>> list(ChainMap(adjustments, baseline))
    ['music', 'art', 'opera']
  • UserDict 对象

    UserDict 类是用作字典对象的外包装。对这个类的需求已部分由直接创建 dict 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字典可以作为属性来访问。

    class collections.UserDict([initialdata])

    模拟一个字典类。这个实例的内容保存为一个正常字典, 可以通过 UserDict 实例的 data 属性存取。如果提供了 initialdata 值, data 就被初始化为它的内容;注意一个 initialdata 的引用不会被保留作为其他用途。

    UserDict 实例提供了以下属性作为扩展方法和操作的支持:

    data

    一个真实的字典,用于保存 UserDict 类的内容。

  • Counter 对象

    一个计数器工具提供快速和方便的计数。

  • class collections.Counter([iterable-or-mapping])

    一个 Counter 是一个 dict 的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。 Counter 类有点像其他语言中的 bags或multisets。

    元素从一个 iterable 被计数或从其他的 mapping (or counter)初始化:

  • from collections import  Counter
    c = Counter(['a','c','a'])
    print(c['a'])
    c = Counter(cat=4,dog=8)
    print(list(c.elements()))
    print(c.most_common(1))
    c = Counter(a=4, b=2, c=0, d=-2)
    d = Counter(a=1, b=2, c=3, d=4)
    c.subtract(d)
    print(c)
    print(list(c.elements()))

    计数器对象除了字典方法以外,还提供了三个其他的方法:

    elements()

    返回一个迭代器,每个元素重复计数的个数。元素顺序是任意的。如果一个元素的计数小于1, elements() 就会忽略它。

  • most_common([n])

    返回一个列表,提供 n 个频率最高的元素和计数。 如果没提供 n ,或者是 None , most_common() 返回计数器中的 所有 元素。相等个数的元素顺序随机.

  • subtract([iterable-or-mapping])

    从 迭代对象 或 映射对象 减去元素。像 dict.update() 但是是减去,而不是替换。输入和输出都可以是0或者负数。

  • 通常字典方法都可用于 Counter 对象,除了有两个方法工作方式与字典并不相同。

    fromkeys(iterable)

    这个类方法没有在 Counter 中实现。

    update([iterable-or-mapping])

    从 迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update() 但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value) 对。

  •  

  • UserList 对象¶

    这个类封装了列表对象。它是一个有用的基础类,对于你想自定义的类似列表的类,可以继承和覆盖现有的方法,也可以添加新的方法。这样我们可以对列表添加新的行为。

    对这个类的需求已部分由直接创建 list 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的列表可以作为属性来访问。

    class collections.UserList([list])

    模拟一个列表。这个实例的内容被保存为一个正常列表,通过 UserList 的 data 属性存取。实例内容被初始化为一个 list 的copy,默认为 [] 空列表。 list 可以是迭代对象,比如一个Python列表,或者一个UserList 对象。

    UserList 提供了以下属性作为可变序列的方法和操作的扩展:

    data

    一个 list 对象用于存储 UserList 的内容。

    子类化的要求: UserList 的子类需要提供一个构造器,可以无参数调用,或者一个参数调用。返回一个新序列的列表操作需要创建一个实现类的实例。它假定了构造器可以以一个参数进行调用,这个参数是一个序列对象,作为数据源。

    如果一个分离的类不希望依照这个需求,所有的特殊方法就必须重写;请参照源代码进行修改。

    UserString 对象

    UserString 类是用作字符串对象的外包装。对这个类的需求已部分由直接创建 str 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字符串可以作为属性来访问。

    class collections.UserString(seq)

    模拟一个字符串对象。这个实例对象的内容保存为一个正常字符串,通过 UserString 的 data 属性存取。实例内容初始化设置为 seq 的copy。seq 参数可以是任何可通过内建 str() 函数转换为字符串的对象。

    UserString 提供了以下属性作为字符串方法和操作的额外支持:

    data

    一个真正的 str 对象用来存放 UserString 类的内容。

你可能感兴趣的:(Python,容器,python,基础)