collections额外数据类型

collections --- 容器数据类型


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

namedtuple()

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

deque

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

ChainMap

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

Counter

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

OrderedDict

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

defaultdict

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

UserDict

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

UserList

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

UserString

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

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__ 属性值就被设置。

命名元组实例没有字典,所以它们要更轻量,并且占用更小内存。

在 3.1 版更改: 添加了对 rename 的支持。

在 3.6 版更改: verbose 和 rename 参数成为 仅限关键字参数.

在 3.6 版更改: 添加了 module 参数。

在 3.7 版更改: 移去了 verbose 参数和属性 _source 。

在 3.7 版更改: 添加了 defaults 参数和 _field_defaults 属性。

>>> # 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)

命名元组尤其有用于赋值 csv sqlite3 模块返回的元组

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print(emp.name, emp.title)

除了继承元组的方法,命名元组还支持三个额外的方法和两个属性。为了防止域名冲突,方法和属性以下划线开始。

classmethod somenamedtuple._make(iterable)

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

>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()

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

>>> p = Point(x=11, y=22)
>>> p._asdict()
OrderedDict([('x', 11), ('y', 22)])

在 3.1 版更改: 返回一个 OrderedDict 而不是 dict 。

somenamedtuple._replace(**kwargs)

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

>>>
>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

>>> for partnum, record in inventory.items():
...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
somenamedtuple._fields

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

>>> p._fields            # view the field names
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
somenamedtuple._field_defaults

默认值的字典。

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

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

>>> getattr(p, 'x')
11

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

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

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

>>> 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(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

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

子类化对于添加和存储新的名字域是无效的。应当通过 _fields 创建一个新的命名元组来实现它:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

文档字符串可以自定义,通过直接赋值给 __doc__ 属性:

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

在 3.5 版更改: 文档字符串属性变成可写。

默认值可以用 _replace() 来实现, 通过自定义一个原型实例:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
>>> janes_account = default_account._replace(owner='Jane')

参见

  • 请参阅 typing.NamedTuple ,以获取为命名元组添加类型提示的方法。 它还使用 class 关键字提供了一种优雅的符号:

    class Component(NamedTuple):
        part_number: int
        weight: float
        description: Optional[str] = None
    
  • 对于以字典为底层的可变域名, 参考 types.SimpleNamespace() 。

  • dataclasses 模块提供了一个装饰器和一些函数,用于自动将生成的特殊方法添加到用户定义的类中。

  • 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 子类的实例,它具有专门用于重新排列字典顺序的方法。

    3.1 新版功能.

    popitem(last=True)

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

    move_to_end(keylast=True)

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

    >>>
    >>> d = OrderedDict.fromkeys('abcde')
    >>> d.move_to_end('b')
    >>> ''.join(d.keys())
    'acdeb'
    >>> d.move_to_end('b', last=False)
    >>> ''.join(d.keys())
    'bacde'
    

    3.2 新版功能.

    相对于通常的映射方法,有序字典还另外提供了逆序迭代的支持,通过 reversed() 。

    OrderedDict 之间的相等测试是顺序敏感的,实现为 list(od1.items())==list(od2.items()) 。 OrderedDict 对象和其他的 Mapping 的相等测试,是顺序敏感的字典测试。这允许 OrderedDict 替换为任何字典可以使用的场所。

    在 3.5 版更改: OrderedDict 的项(item),键(key)和值(value) 视图 现在支持逆序迭代,通过 reversed() 。

    在 3.6 版更改: PEP 468 赞成将关键词参数的顺序保留, 通过传递给 OrderedDict 构造器和它的 update() 方法。

    OrderedDict 例子和用法

    创建记住键值 最后 插入顺序的有序字典变体很简单。 如果新条目覆盖现有条目,则原始插入位置将更改并移至末尾:

    class LastUpdatedOrderedDict(OrderedDict):
        'Store items in the order the keys were last added'
    
        def __setitem__(self, key, value):
            super().__setitem__(key, value)
            super().move_to_end(key)
    

    一个 OrderedDict 对于实现 functools.lru_cache() 的变体也很有用:

    class LRU(OrderedDict):
        'Limit size, evicting the least recently looked-up key when full'
    
        def __init__(self, maxsize=128, *args, **kwds):
            self.maxsize = maxsize
            super().__init__(*args, **kwds)
    
        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

 

 

posted @ 2019-11-20 19:26  花红正合嗅  阅读(290)  评论(0编辑  收藏  举报