python collections 模块 namedtuple defaultdict OrderedDict ChainMap Counter UserDict deque

目录

collectons 

collections.namedtuple 

collections.defaultdict

collections.OrderedDict

collections.ChainMap

collections.Counter

colllections.UserDict


collectons 

collections.namedtuple 

collections.namedtuple 创建具名元组,也就是创建一个带字段名的元组和一个有名字的类,namedtuple创建的类不会用__dict__来存放这些实例的属性,所以namedtuple类的实例跟普通对象实例要小一些,消耗的内存跟元组是一样的。

 创建一个具名元组需要两个参数,一个类名,一个类的各个字段的名字。另外字段的名字可以有两种写法一种是由数个字符串组成的可迭代对象,例如

Person = collections.namedtuple('Person',['age','name'])

 第二种是由空格分隔开的字段名组成的字符串

Person = collections.namedtuple('Person','age name')

 看《flutter python》上的例子

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates') 
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) 
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
139.691667))
>>> tokyo.population 
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'

 具名元组除了跟普通元组相同的属性外,还有自卸自己特有的属性,例如:_fields类属性、类方法_make(iterable)和实例方法_asdict()

>>> City._fields 
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data) 
>>> delhi._asdict() 
OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population',
21.935), ('coordinates', LatLong(lat=28.613889, long=77.208889))])
>>> for key, value in delhi._asdict().items():
print(key + ':', value)
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
>>>

 collections.defaultdict

一个字典就是一个键对应一个单值的映射。如果你想要一个键映射多个值,那么你就需要将这多个值放到另外的容器中,比如列表或者集合里面.collections 模块中的defaultdict 来构造这样的字典。defaultdict 的一个特征是它会自动初始化每个key 刚开始对应的值,所以你只需要关注添加元素操作了

>>>from collections import defaultdict
>>>d = defaultdict(list)
>>>d['a'].append(1)
>>>d['a'].append(2)
>>>d['b'].append(4)
>>>d = defaultdict(set)
>>>d['a'].add(1)
>>>d['a'].add(2)
>>>d['b'].add(4)

在用户创建 defaultdict 对象的时候,就需要给它配置一个为找不到的键创造默认值的方法。

defaultdict对象的内部实现原理是,我们知道在d[k]获取键值对的时候会调用__getitem__方法,对于普通的dict或者get(k)方法如果键不存在会报异常,而defaultdict调用__getitem__方法键不存在会调用__missing__方法,创造一个默认值。

__miss__方法在dict类中是不存在的,所以在在继承类中实现,例如

class StrKeyDict0(dict):  # <1>

    def __missing__(self, key):
        if isinstance(key, str): 
            raise KeyError(key)
        return self[str(key)]  

    def get(self, key, default=None):
        try:
            return self[key] 
        except KeyError:
            return default  

    def __contains__(self, key):
        return key in self.keys() or str(key) in self.keys() 

 字典内部 setdefault() 方法也可以代替

d = {} # A regular dictionary
d.setdefault('a', []).append(1)
d.setdefault('a', []).append(2)
d.setdefault('b', []).append(4)

collections.OrderedDict

创建一个字典,并且在迭代或序列化这个字典的时候能够控制元素的顺序。

from collections import OrderedDict
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
# Outputs "foo 1", "bar 2", "spam 3", "grok 4"
for key in d:
    print(key, d[key])

当你想要构建一个将来需要序列化或编码成其他格式的映射的时候,OrderedDict是非常有用的。比如,你想精确控制以JSON 编码后字段的顺序,你可以先使用OrderedDict 来构建这样的数据:

>>> import json
>>> json.dumps(d)
'{"foo": 1, "bar": 2, "spam": 3, "grok": 4}'

OrderedDict 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候,它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。
这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False) 这样调用它,那么它删除并返回第一个被添加进去的元素。

collections.ChainMap

该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到

假如你有如下两个字典: 

a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }

现在假设你必须在两个字典中执行查找操作(比如先从a 中找,如果找不到再在b中找)。一个非常简单的解决方案就是使用collections 模块中的ChainMap 类

from collections import ChainMap
c = ChainMap(a,b)
print(c['x']) # Outputs 1 (from a)
print(c['y']) # Outputs 2 (from b)
print(c['z']) # Outputs 3 (from a)

如果出现重复键,那么第一次出现的映射值会被返回。因此,例子程序中的c['z']总是会返回字典a 中对应的值,而不是b 中对应的值。对于字典的更新或删除操作总是影响的是列表中第一个字典。

>>> len(c)
3
>>> list(c.keys())
['x', 'y', 'z']
>>> list(c.values())
[1, 2, 3]

>>> c['z'] = 10
>>> c['w'] = 40
>>> del c['x']
>>> a
{'w': 40, 'z': 10}

collections.Counter

这个映射类型会给键准备一个整数计数器。每次更新一个键的时候都会增加这个计数器。所以这个类型可以用来给可散列表对象计数,或者是当成多重集来用——多重集合就是集合里的元素可以出现不止一次 

most_common([n]) 会按照次序返回映射里最常见的 n 个键和它们的计数

>>> ct = collections.Counter('abracadabra')
>>> ct
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.update('aaaaazzz')
>>> ct
Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.most_common(2)
[('a', 10), ('z', 3)]

 colllections.UserDict

这个类其实就是把标准 dict 用纯 Python 又实现了一遍。UserDict 是让用户继承写子类的,跟 OrderedDict、ChainMap 和 Counter 这些开箱即用的类型不同

UserDict并不是dict的子类,但UserDict有个属性叫data是dict的实例,,这个属性实际上是 UserDict 最终存储数据的地方。

import collections
class StrKeyDict(collections.UserDict): 
    def __missing__(self, key): 
        if isinstance(key, str):
            raise KeyError(key)
        return self[str(key)]
    def __contains__(self, key):
        return str(key) in self.data 
    def __setitem__(self, key, item):
        self.data[str(key)] = item 

collectios.deque

deque类是一个双向队列,可以快速在两端添加或者删除元素的数据类型,从队列中间删除元素的操作会慢一些,因为它只对在头尾的操作进行了优化。append 和 popleft 都是原子操作,也就说是 deque 可以在多线程程序中安全地当作先进先出的栈使用,而使用者不需要担心资源锁的问题。

有一个可选参数 maxlen,代表这个队列可以容纳的元素的数量,而且设定后,这个属性不能修改。如果队列已满,在队列尾部添加操作时,队列的头部元素会被删除

rotate 队列的旋转操作,接受一个参数n,当n>0时,队列的最右边的n个元素会被移动队列的左边。当n<0时,最左边的n个元素会被移动到右边

extendleft(iter) 方法会把迭代器里的元素逐个添加到双向队列的左边,因此迭代
器里的元素会逆序出现在队列里

>>> from  collections import deque
>>> dq = deque(range(10),maxlen=10)
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3)
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1)
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11,22,33])
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10,20,30,40])
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值