python:collections模块 — 容器数据类型

参考文档:collections --- 容器数据类型 — Python 3.10.1 文档

简介

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

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

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

使用示例:

>>> Point = namedtuple('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
>>> p                            # __repr__
Point(x=11, y=22)

collecitons.namedtuple(typename, field_name, *, rename=False, defaults=None, module=None)

        返回一个新的元组子类,名为typaname

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

        rename:如果为真,无效字段名会自动传换成位置名。比如['abc', 'def', 'abc']转换成[

'abc', '_1', '_2']

        defaults: 可以为None,或者是一个默认值的iterable。作为字段默认值出现,如果defaults为iterable,且长度小于字field_name的长度,那么defaults就应用到最右边的参数。比如field_name为['x', 'y', 'z'],default为(1,2),那么x就必须指定一个参数值,y默认值为1,z默认值2.

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

用于赋值 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)

   namedtuple支持的三个方法和两个属性

somenamedtuple._make(iterable)   
# 从存在的序列或迭代实例创建一个新实例

somenamedtuple._asdict()         
# 返回一个新dict,将值映射到字段名

somenamedtuple._replace(**kwargs) 
# 返回一个新的命名元组实例,并将指定域替换为新的值

somenamedtuple._fields   
# 列出字段名

somenamedtuple._field_defaults   
# 将字段名映射到默认值

方法和属性使用示例:

>>> t = [11, 22]
>>> Point._make(t)          # _make(iterable)
Point(x=11, y=22)

>>> p = Point(x=11, y=22)
>>> p._asdict()             # _asdict()
{'x':11, 'y':22}

>>> p._replace(x=33)        # _replace(**kwargs)
Point(x=33, y=22)


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

>>>p._fields        # _fields
('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=22m red=128, green=255, blue=0)


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

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

namedtuple一些其他使用:

>>> d = {'x':11, 'y':22}
>>> Point(**d)                  # 转换字典到一个元组
Point(x=11,y=22)

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


>>> Book = namedtuple('Book', ['id', 'title', 'authors'])   # 通过__doc__添加说明文档
>>> Book.__doc__ += "Hardcover book in active collection"
>>> Book.id.__doc__ = '13-digit ISBN'

2. deque对象

class collections.deque([iterable[,maxlen]])

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

        如果maxlen没有指定或者是None,则deque可以增长到任意长度,否则,增长到指定长度。一旦限定长度的deque满了,当新项添加时,则相同数量的项从另一端弹出

deque支持的一些方法

append(x)    
# 添加x到右端

appendleft(x)    
# 添加x到左端

clear()    
# 移除所有元素,使其长度为0

copy()    
# 创建一个浅拷贝

count(x)    
# 计算deque中元素等于x的个数

extend(iterable)    
# 扩展deque的右端,通过添加iterable中的元素

extentleft(iterable)    
# 扩展deque的左端,通过添加iterable中的元素。但是,添加在左端时,iterable中的元素将会被反过来添加

index(x[,start[,stop]])    
# 返回x在deque中的位置(在索引start之后,索引stop之前),返回第一个匹配项,如果未找到,引发ValueError异常

insert(i, x)    
# 在位置i中插入x;如果插入x会使限定长度的deque的长度超出maxlen,则引发 IndexError异常

pop()    
# 移除deque最右端的元素并返回该元素,如果deque为空,则引发IndexError

popleft()    
# 移除deque最左端的元素并返回该元素,如果deque为空,则引发IndexError

remove(value)    
# 移除找到第一个value,如果没有,则引发ValueError

reverse()    
# 将deque逆序排列,返回None

rotate(n)    
# deque向右循环n步,如果n为负数,则向左循环;如果deque不为空,deque每向右循环一步就等价于d.appendleft(d.pop()),deque每向左循环一步就等价于d.append(popleft())

maxlen    
# deque提供的一个只读属性,deque的最大尺寸,没有指定则为None

# 注:索引访问两端的复杂度都为O(1), 但在中间则会降低为O(n),如需快速随机访问,请改用列表

  deque的多种用法示例

def tail(filename, n=3):
    """
    限长的deque提供了类似Unix tail的功能
    """
    # Return the last n lines of file
    with open(filename) as f:
        return deque(f, n)
def moving_average(iterable, n=3):
    """
    维护一个近期添加元素的序列,通过从右边添加和左边弹出
    """
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
    # http://en.wikipedia.org/wiki/Moving_average
    it = iter(iterable)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = sum(d)
    for elem in it:
        s += elem - d.popleft()
        d.append(elem)
        yield s / n

for average in moving_average([40, 30, 50, 46, 39, 44]):
    print(average )

        
def roundrobin(*iterables):
    """
    轮询调度器
    """
    # roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    iterators = deque(map(iter, iterables))
    while iterators:
        try:
            while True:
                yield next(iterators[0])
                iterators.rotate(-1)
        except StopIteration:
            # Remove an exhausted iterator.
            iterators.popleft()
def delete_nth(d, n):
    """
    通过rotate()实现deque切片和删除
    """
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

3. ChainMap对象

使用示例1:

from collections import ChainMap


a = {"name": "bob"}
b = {"age": 18}

d = ChainMap(a, b)
print(d)  # ChainMap({'name': 'bob'}, {'age': 18})
print(d.maps)  # [{'name': 'bob'}, {'age': 18}]
b["age"] = 23
print(d)  # ChainMap({'name': 'bob'}, {'age': 23})
e = d.new_child()
print(e)    # ChainMap({}, {'name': 'bob'}, {'age': 23})
print(e.parents)    # ChainMap({'name': 'bob'}, {'age': 23})
e['name'] = 'Ada'
e['age'] = 55
d['name'] = "Alice"
print(e)    # ChainMap({'name': 'Ada', 'age': 55}, {'name': 'Alice'}, {'age': 23})
print(e.parents)    # ChainMap({'name': 'Alice'}, {'age': 23})
print(d.parents)    # ChainMap({'age': 23})

class collections.ChainMap(*maps)

        一个ChainMap将多个字典或者其它映射组合在一起,创建一个单独的可更新的视图。如果没有maps被指定,就提供一个默认的空字典,如下示例:

a = ChainMap()
print(a)   # ChainMap({})

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

a = {"name": "bob"}
b = ChainMap(a)
print(b)  # ChainMap({'name': 'bob'})
a['name'] = 'Ada'
print(b)  # ChainMap({'name': 'Ada'})

   ChainMap支持所有的字典方法,另外还支持如下属性和方法:

maps    
# 属性,一个可以更新的映射列表,至少包含一个映射

new_child(m=None, **kwargs)    
# 方法,返回一个新的ChainMap,包含一个新的映射,和当前实例中的所有映射。如果m被指定,它会成为新的映射添加在当前的列表中;如果m为None,调用d.new_chile(),则等价于ChainMap({}, *d.maps)。如                                                                                                 果指定了任何关键字参数,它们则会更新传入的映射或者字典,此方法被用于创建上下文,它可在不改变任何上级映射的前提下更新映射

parents   
# 属性返回一个新的ChainMap包含当前实例的所有的映射,除了第一个。一个d.parents等价于ChainMap(*d.maps[1:])

ChainMap的使用示例:

"""
ChainMap只更新第一个映射,通过子类实现ChainMap的深度写和删除
"""
from collections import ChainMap


class DeepChainMap(ChainMap):

    def __setitem__(self, key, value):
        for elem in self.maps:
            if key in elem:
                elem[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for elem in self.maps:
            if key in elem:
                del elem[key]
                return 
        raise KeyError(key)


d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
d['lion'] = 'orange'         # update an existing key two levels down
d['snake'] = 'red'           # new keys get added to the topmost dict
del d['elephant']            # remove an existing key one level down
print(d)    # DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

4. Counter

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

       一个Counter是一个dict的子类,用于计数可哈希对象。它是一个集合,元素像字典键一样存储,它们的计数存储为值。计数可以任何整数值,包括0和负数

Counter初始化示例:

>>> c = Counter()        # a new, empty Counter
>>> c = Counter("hello,world")    # a new Counter from an iterable
>>> c = Counter({"color":"red", "food":"tomato"})    # a new Counter from a mapping
>>> c = Counter(color="red", food="tomato")    # a new Counter from keyword args

如果访问的键,不在Counter, 会返回0

>>> c = Counter("hello,world")
>>> print(c['a'])    # 0

移除一个键,需要使用del

c = Counter("hello,world")
del c['h']
print(c)    # Counter({'l': 3, 'o': 2, 'e': 1, ',': 1, 'w': 1, 'r': 1, 'd': 1})

Counter支持的一些属性和方法:


elements()    
# 返回一个迭代器,其中每个元素将重复出现计数值指定次。元素会按首次出现的顺序返回。如果某个元素计数值小于一,elements()将忽略该元素

most_common([n])    
# 返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排列。如果n省略为None, 则返回计数器中的所有元素。计数值相当的元素按首次出现的顺序排列;在值需要排序的时候使用

subtract([iterable-or-mapping])    
# 从迭代对象或映射对象中减去元素

total()    
# 统计总计数值

update([iterable-or-mapping])    
# 从迭代对象或映射对象中添加元素

Counter一些使用示例:

>>> c = Counter("hello")
>>> sorted(c.elements())  
['e', 'h', 'l', 'l', 'o']
>>> c.most_common(2)
[('l', 2), ('h', 1)]
>>> d = Counter({'l': 3})
>>> c.subtract(d)
Counter({'h': 1, 'e': 1, 'o': 1, 'l': -1})
>>> c.update(d)
Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
>>>list(c)
['h', 'e', 'l', 'o']
>>> set(c)
{'o', 'e', 'h', 'l'}
>>> dict(c)
{'h': 1, 'e': 1, 'l': 2, 'o': 1}
>>> c.items()
dict_items([('h', 1), ('e', 1), ('l', 2), ('o', 1)])
>>> +c        # 删除0和负数计数
Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
>>> c.clear()
None

提供了几个数学操作,可以结合 Counter 对象,以生产 multisets (计数器中大于0的元素)。 加和减,结合计数器,通过加上或者减去元素的相应计数。交集和并集返回相应计数的最小或最大值。每种操作都可以接受带符号的计数,但是输出会忽略掉结果为零或者小于零的计数。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x]) 
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

5. OrderedDict 对象

有序字典比常规字典更擅长排序,是个需要频繁排序的操作

class collections.OrderedDict([item])

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

OrderDict支持的一些方法


popitem(last=True)    
# 移除并返回一对(key,value)键值对;如果last为真,则按照LIFO后进先出的顺序返回键值对,否则,按照FIFO先进先出

move_to_end(key, last=True)    
# 将已存在的key移到OrderDict的一端,如果last为True,则移动到最右端,如果last为False,则移动的开端;如果key不存在,则抛出KeyError

6. defaultdict 对象

class collection.defaultdict(default_factory=None, /[,....])

        返回一个新的类似字典的对象,defaultdict是内置dict的子类。它重载了一个方法并添加了一个可写的实例变量

        本对象包含一个名为default_factory的属性。构造defaultdict对象是,传入的第一个参数会被设为default_factory的初始值,如果没传,默认为None。其他所有参数(包括关键字参数)都相当于传给dict的构造函数。

defaultdict支持的一些方法和属性


__missing__(key)
    # 如果default_factory为None,调用该方法会抛出KeyError异常,附带参数key
    # 如果default_factory不为None,则它会被(不带参数)调来为key提供一个默认值,这个值和key作为一对键值对插入到字典中,并作为本方法的返回值返回
    # 如果调用default_factory的过程中出现异常,这个异常会被原封不动的向外层传递
    # 在无法找到所需键值对时,本方法会被dict的__getitem__()方法调用。无论本方法返回了值还是抛出了异常,都会被__getitem__()传递
    # 注意,__missing__()不会被除__getitem__()以外的方法调用。意味着get()会像正常的dict返回None,而不是default_factory

default_factory
    # 本属性由__missig__()方法调用。

defaultdict使用示例:

"""
使用defaultdict,将一个(键-值对)序列转化为(键-列表)字典
"""
from collections import defaultdict

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)    
# defaultdict(, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
"""
default_factory设置为int, 使defaultdict用于计数
"""
from collections import defaultdict

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(int)
for k, v in s:
    d[k] += v

print(d)  # defaultdict(, {'yellow': 4, 'blue': 6, 'red': 1})

"""
使用lamdba函数,更灵活的提供默认值
"""
def constant_factory(value):
    return lambda: value


d = defaultdict(constant_factory(''))
d.update(name='John', action='ran')
e = '%(name)s %(action)s to %(object)s' % d
print(e)    # John ran to 
"""
设置 default_factory 为 set 使 defaultdict 用于构建 set 集合
"""
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = defaultdict(set)
for k, v in s:
    d[k].add(v)

print(sorted(d.items()))    # [('blue', {2, 4}), ('red', {1, 3})]

7. UserDict objects

UserDict类用作字典对象的外包装,如果想要对dict的功能进行扩展,可以使用此类。

class collections.UserDict([initialdata])

        模拟字典的类。 这个实例的内容保存在一个常规字典中,它可以通过 UserDict 实例的 data 属性来访问。 如果提供了 initialdata,则 data 会用其内容来初始化;请注意对 initialdata 的引用将不会被保留,以允许它被用于其他目的。

UserDict实例支持的属性:

​
data

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

​

8.UserList objects

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

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

class collections.UserList([list])

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

UserList实例支持的属性:

​
data

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

​

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

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

9. UserString object

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

class collections.UserString(seq)                         

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

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

​
data

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

​

在 3.5 版更改: 新方法 __getnewargs____rmod__casefoldformat_mapisprintable, 和 maketrans

你可能感兴趣的:(Python,python,开发语言,后端)