Python的collections模块
collections --- 容器数据类型
Python3 collections模块使用详解
collections — Container datatypes namedtuple(): 生成可以使用名字来访问元素内容的tuple子类 deque: 双端队列,可以快速的从另外一侧追加和推出对象 Counter: 计数器,主要用来计数 OrderedDict: 有序字典 defaultdict: 带有默认值的字典 ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面 UserDict 封装了字典对象,简化了字典子类化 UserList 封装了列表对象,简化了列表子类化 UserString 封装了列表对象,简化了字符串子类化 collections.abc 抽象基类
tuple的几个特性:
tuple比list好的地方 4.1 immutable的重要性:性能优化(元素全为immutable的会作为常量在编译时确定)、线程安全、可以作为dict的key,拆包特性 4.2 tuple类似struct,list类似array
容器序列
list
、tuple
和 collections.deque
这些序列能存放不同类型的数据。
扁平序列
str
、bytes
、bytearray
、memoryview
和 array.array
,这类序列只能容纳一种类型。
容器序列 存放的是它们所包含的任意类型的对象的引用,而扁平序列 里存放的是值而不是引用。换句话说,扁平序列其实是一段连续的内存空间。由此可见扁平序列其实更加紧凑,但是它里面只能存放诸如字符、字节和数值这种基础类型。
序列类型还能按照能否被修改来分类。
可变序列
list
、bytearray
、array.array
、collections.deque
和 memoryview
。
不可变序列
tuple
、str
和 bytes
。
具名元组namedtuple
概念
命名的元组,意味给元组中的每个位置赋予含义,意味着代码可读性更强,namedtuple可以在任何常规元素使用的地方使用,而且它可以通过名称来获取字段信息而不仅仅是通过位置索引。用以构建只有少数属性但是没有方法的对象,比如数据库条目。
collections.namedtuple
是一个工厂函数,它可以用来构建一个带字段名的元组和一个有名字的
用 namedtuple
构建的类的实例所消耗的内存跟元组是一样的,因为字段名都被存在对应的类里面
创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。
几个最有用的:_fields
类属性、类方法 _make(iterable)
和实例方法 _asdict()
。
❶ _fields
属性是一个包含这个类所有字段名称的元组。
❷ 用 _make()
通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟 City(*delhi_data)
是一样的。
❸ _asdict()
把具名元组以 collections.OrderedDict
的形式返回,我们可以利用它来把元组里的信息友好地呈现出来。
复制 from collections import namedtuple
User = namedtuple ( "USER" , [ "name" , "age" , "city" , "height" ])
user_1 = User (name = "雷鸣" , age = 21 , city = "北京" , height = "175" )
print ( "user_1" , user_1.name, user_1.age, user_1.city, user_1.height)
user_1 雷鸣 21 北京 175
user_1 . _fields
Out [ 4 ]: ( 'name' , 'age' , 'city' , 'height' )
使用
定义
代码
复制 # namedtuple: 生成可以使用名字来访问元素内容的tuple子类
# -*- coding: utf-8 -*
from collections import namedtuple
User = namedtuple ( "USER" , [ "name" , "age" , "city" , "height" ])
user_1 = User (name = "雷鸣" , age = 21 , city = "北京" , height = "175" )
print ( "user_1" , user_1.name, user_1.age, user_1.city, user_1.height)
user_tuple = ( "雷姆" , 17 , '异世界' )
user_2 = User ( * user_tuple, "172" )
print ( "user_2" , user_2.name, user_2.age, user_2.city, user_2.height)
user_dict = {
"name" : "雷玖" ,
"age" : "17" ,
"city" : "异世界" ,
}
user_3 = User ( ** user_dict, height = "172" )
print ( "user_3" , user_3.name, user_3.age, user_3.city, user_3.height)
user_tuple_2 = ( "雷姆" , 17 , '异世界' , "172" )
user_list_2 = [ "雷姆" , 17 , '异世界' , "172" ]
user_dict_2 = {
"name" : "雷玖" ,
"age" : "17" ,
"city" : "异世界" ,
"height" : "172"
}
user_4 = User . _make (user_dict_2. values ())
print ( "user_4" , user_4.name, user_4.age, user_4.city, user_4.height)
user_5 = User . _make (user_tuple_2)
print ( "user_5" , user_5.name, user_5.age, user_5.city, user_5.height)
user_6 = User . _make (user_list_2)
print ( "user_6" , user_6.name, user_6.age, user_6.city, user_6.height)
输出
复制 user_1 雷鸣 21 北京 175
user_2 雷姆 17 异世界 172
user_3 雷玖 17 异世界 172
user_4 雷玖 17 异世界 172
user_5 雷姆 17 异世界 172
user_6 雷姆 17 异世界 172
访问
代码
复制 from collections import namedtuple
User = namedtuple ( "USER" , [ "name" , "age" , "city" , "height" ])
user_tuple = ( "雷姆" , 17 , '异世界' )
user_2 = User ( * user_tuple, "172" )
print (user_2. _asdict ())
item = ( 'a' , 'b' , 'a' , 'a' , 5 )
for it in set (item):
print ( f ' { it } 出现了 { item. count (it) } 次' )
输出
复制 OrderedDict ([( 'name', '雷姆'), ('age', 17), ('city', '异世界'), ('height', '172')])
a 出现了3次
5 出现了1次
b 出现了1次
字典
介绍
dict
类型不但在各种程序里广泛使用,它也是 Python 语言的基石。
跟它有关的内置函数都在 __builtins__.__dict__
模块中。
正是因为字典至关重要,Python 对它的实现做了高度优化,而散列表 则是字典类型性能出众的根本原因。
collections.abc
模块中有 Mapping
和 MutableMapping
这两个抽象基类
然而,非抽象映射类型一般不会直接继承这些抽象基类,它们会直接对 dict
或是 collections.UserDict
进行扩展。
标准库里的所有映射类型都是利用 dict
来实现的,因此它们有个共同的限制,即只有可散列的 数据类型才能用作这些映射里的键
关于可散列类型的定义有这样一段话:
如果一个对象是可散列的,那么在这个对象的生命周期中,它的散列值是不变的,而且这个对象需要实现 __hash__()
方法。另外可散列对象还要有 __qe__()
方法,这样才能跟其他键做比较。如果两个可散列对象是相等的,那么它们的散列值一定是一样的
一般来讲用户自定义的类型的对象都是可散列的,散列值就是它们的 id()
函数的返回值,所以所有这些对象在比较的时候都是不相等的
创建字典的不同方式:
复制 >>> a = dict (one = 1 , two = 2 , three = 3 )
>>> b = { 'one' : 1 , 'two' : 2 , 'three' : 3 }
>>> c = dict ( zip ([ 'one' , 'two' , 'three' ], [ 1 , 2 , 3 ]))
>>> d = dict ([( 'two' , 2 ), ( 'one' , 1 ), ( 'three' , 3 )])
>>> e = dict ({ 'three' : 3 , 'one' : 1 , 'two' : 2 })
>>> a == b == c == d == e
True
除了这些字面句法和灵活的构造方法之外,字典推导 (dict comprehension)也可以用来建造新 dict
字典推导 (dictcomp)可以从任何以键值对作为元素的可迭代对象中构建出字典。
映射类型的方法其实很丰富。表 3-1 为我们展示了 dict
、defaultdict
和 OrderedDict
的常见方法,后面两个数据类型是 dict
的变种,位于 collections
模块内。
字典的变种 :
collections.OrderedDict : 这个类型在添加键的时候会保持顺序,因此键的迭代次序总是一致的。OrderedDict
的 popitem
方法默认删除并返回的是字典里的最后一个元素,但是如果像 my_odict.popitem(last=False)
这样调用它,那么它删除并返回第一个被添加进去的元素。
collections.ChainMap : 该类型可以容纳数个不同的映射对象,然后在进行键查找操作的时候,这些对象会被当作一个整体被逐个查找,直到键被找到为止。
collections.Counter : 这个映射类型会给键准备一个整数计数器。每次更新一个键的时候都会增加这个计数器。所以这个类型可以用来给可散列表对象计数,或者是当成多重集来用——多重集合就是集合里的元素可以出现不止一次。
跟 OrderedDict
、ChainMap
和 Counter
这些开箱即用的类型不同,UserDict
是让用户继承写子类的。
dict
的实现及其导致的结果
键必须是可散列的
一个可散列的对象必须满足以下要求。
(1) 支持 hash()
函数,并且通过 __hash__()
方法所得到的散列值是不变的。
(2) 支持通过 __eq__()
方法来检测相等性。
(3) 若 a == b
为真,则 hash(a) == hash(b)
也为真。
所有由用户自定义的对象默认都是可散列的,因为它们的散列值由 id()
来获取,而且它们都是不相等的。
字典在内存上的开销巨大
由于字典使用了散列表,而散列表又必须是稀疏的,这导致它在空间上的效率低下。
在用户自定义的类型中,__slots__
属性可以改变实例属性的存储方式,由 dict
变成 tuple
键查询很快
dict
的实现是典型的空间换时间:字典类型有着巨大的内存开销,但它们提供了无视数据量大小的快速访问——只要字典能被装在内存里
键的次序取决于添加顺序
当往 dict
里添加新键而又发生散列冲突的时候,新键可能会被安排存放到另一个位置。
往字典里添加新键可能会改变已有键的顺序
无论何时往字典里添加新的键,Python 解释器都可能做出为字典扩容的决定。扩容导致的结果就是要新建一个更大的散列表,并把字典里已有的元素添加到新表里。
defaultdict默认值词典
错误方式
代码
复制 # 错误方式一
student_grades = {}
grades = [( 'elliot' , 91 ) , ( 'neelam' , 98 ) ,
( 'bianca' , 81 ) , ( 'elliot' , 88 )]
for name , grade in grades :
if name not in student_grades :
student_grades [ name ] = []
student_grades [ name ]. append (grade)
print (student_grades)
# 错误方式二
student_grades = {}
for name , grade in grades :
student_grades . setdefault (name, [])
student_grades [ name ]. append (grade)
print (student_grades)
输出
复制 {'elliot': [91, 88], 'neelam': [98], 'bianca': [81]}
{'elliot': [91, 88], 'neelam': [98], 'bianca': [81]}
正确方式
在这种情况下,你将创建一个defaultdict,它使用不带参数的list构造函数作为默认方法。没有参数的list返回一个空列表,因此如果名称不存在则defaultdict调用list(),然后再把学生成绩添加上。如果你想更炫一点,你也可以使用lambda函数作为值来返回任意常量。
在用户创建 defaultdict
对象的时候,就需要给它配置一个为找不到的键创造默认值的方法。
实例化一个 defaultdict
的时候,需要给构造方法提供一个可调用对象
把 list
构造方法作为 default_factory
来创建一个 defaultdict
。
defaultdict
里的 default_factory
只会在 __getitem__
里被调用,在其他的方法里完全不会发挥作用。比如,dd
是个 defaultdict
,k
是个找不到的键, dd[k]
这个表达式会调用 default_factory
创造某个默认值,而 dd.get(k)
则会返回 None
。
所有的映射类型在处理找不到的键的时候,都会牵扯到 __missing__
方法。这也是这个方法称作“missing”的原因
如果有一个类继承了 dict
,然后这个继承类提供了 __missing__
方法,那么在 __getitem__
碰到找不到的键的时候,Python 就会自动调用它
__missing__
方法只会被 __getitem__
调用
像 k in my_dict.keys()
这种操作在 Python 3 中是很快的,而且即便映射类型对象很庞大也没关系。这是因为 dict.keys()
的返回值是一个“视图”。视图就像一个集合,而且跟字典类似的是,在视图里查找一个元素的速度很快。
代码
复制 # 正确方式
from collections import defaultdict
student_grades = defaultdict ( list )
[student_grades [ name ]. append (grade) for name , grade in grades]
print (student_grades)
输出
复制 defaultdict ( <class 'list'>, {'elliot': [91, 88], 'neelam': [98], 'bianca': [81]})
统计缺失多少键
复制 class CountMissing :
... : def __init__ ( self ):
... : self . added = 0
... : def missing ( self ):
... : self . added += 1
... : return 0
... :
current = { 'green' : 12 , 'blue' : 3 }
increments = [( 'red' , 5 ) , ( 'blue' , 17 ) , ( 'orange' , 9 )]
counter = CountMissing ()
from collections import defaultdict
result = defaultdict (counter.missing, current)
for key , amount in increments :
... : result [ key ] += amount
... :
print (counter.added)
2
其它默认值
代码
复制 # 错误方式
cowboy = { 'age' : 32 , 'horse' : 'mustang' , 'hat_size' : 'large' }
if 'name' in cowboy :
name = cowboy [ 'name' ]
else :
name = 'The Man with No Name'
print (name)
# 如果你想在仍然访问name的key时使用默认值更新字典
# 错误方式
if 'name' not in cowboy :
cowboy [ 'name' ] = 'The Man with No Name'
name = cowboy [ 'name' ]
print (name)
# 正确方式
# get()执行与第一种方法相同的操作,但现在它们会自动处理。如果key存在,则返回适当的值。否则,将返回默认值
name = cowboy . get ( 'name' , 'The Man with No Name' )
print (name)
# 正确方式
name = cowboy . setdefault ( 'name' , 'The Man with No Name' )
print (name)
from collections import defaultdict
dic = defaultdict ( lambda : '0a' )
dic [ 'a' ]
Out [ 41 ]: '0a'
输出
复制 The Man with No Name
The Man with No Name
The Man with No Name
The Man with No Name
有序词典OrderedDict
概念
OrderedDict类似于正常的词典,只是它记住了元素插入的顺序,当在有序的词典上迭代时,返回的元素就是它们第一次添加的顺序。
class collections.OrderedDict ,返回已给dict的子类,支持常规的dict的方法,OrderedDict是一个记住元素首次插入顺序的词典,如果一个元素重写已经存在的元素,那么原始的插入位置保持不变,如果删除一个元素再重新插入,那么它就在末尾。
使用
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序
例子1
代码
复制 # 例子1
from collections import OrderedDict
odd0 = { 'banana' : 3 , 'apple' : 4 }
od1 = OrderedDict ({ 'banana' : 3 , 'apple' : 4 })
od2 = OrderedDict ({ 'apple' : 4 , 'banana' : 3 })
print (od1 == od2)
print (od1 == odd0)
# 例子2
from collections import OrderedDict
od1 = OrderedDict ({ 'banana' : 3 , 'apple' : 4 })
# OrderedDict.popitem(last=True),popitem方法返回和删除一个(key,value)对,如果last=True,就以LIFO方式执行,否则以FIFO方式执行。
od1 . popitem ( False )
print (od1)
od1 . pop ( 'apple' ) # 这里必须提供key
print (od1)
输出
复制 False
True
OrderedDict ([( 'apple', 4)])
OrderedDict ()
例子2
复制 # 例子3
from collections import OrderedDict
od1 = OrderedDict ({ 'banana' : 3 , 'apple' : 4 })
od1 . move_to_end ( 'banana' )
print (od1)
# 例子4
# OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key
from collections import OrderedDict
class LastUpdatedOrderedDict ( OrderedDict ):
def __init__ ( self , capacity ):
super (LastUpdatedOrderedDict, self). __init__ ()
self . _capacity = capacity
def __setitem__ ( self , key , value ):
containsKey = 1 if key in self else 0
if len (self) - containsKey >= self . _capacity :
last = self . popitem (last = False )
print ( 'remove:' , last)
if containsKey :
del self [ key ]
print ( 'set:' , (key, value))
else :
print ( 'add:' , (key, value))
OrderedDict . __setitem__ (self, key, value)
复制 OrderedDict ([( 'apple', 4), ('banana', 3)])
ChainMap
原始的映射对象被存放在一个列表中构成一个字典序列self.maps
在 ChainMap
中查询某个键时,会对原始的映射对象依次查询,直至找到这个键,若未找到,则默认引发 KeyError
异常。
在 ChainMap
中进行插入、更新、删除时,只会对原始映射中的第一个映射进行操作
ChainMap 对象除了 maps 属性外,还具有一个 parents 属性和 new_child(m=None) 方法。
parents 属性返回了一个不包含原始映射中的第一个映射的 ChainMap 对象,对应源码中 self.class (*self.maps[1:]) ,其效果和 ChainMap(*d.maps[1:]) 相同
new_child(m=None) 方法返回一个包含指定映射 m(未指定时,为空字典)及其他原有映射的 ChainMap 对象,其中指定映射位于底层 maps 列表首位,在其他原有映射之前。
复制 # ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多
from collections import ChainMap
a = { 'a' : 1 , 'b' : 2 }
b = { 'c' : 3 }
c = ChainMap (a, b) # 如果有重复的key,以第一次为准
print (c)
# 将数据以列表形式展现,实际上是将链接指向原来的实现
print (c.maps)
print (c.maps[ 0 ][ 'b' ])
ChainMap ({ 'a' : 1 , 'b' : 2 }, { 'c' : 3 })
[ { 'a' : 1 , 'b' : 2 }, { 'c' : 3 } ]
2
# 简单应用
一个Python命令中,如果在命令行中输入参数则使用该参数,没有则从OS环境变量中获取,如果还没有再取自定义默认值
import os
import argparse
from collections import ChainMap
defaults = { 'color' : 'red' , 'user' : 'guest' }
parser = argparse . ArgumentParser ()
parser . add_argument ( '-u' , '--user' )
parser . add_argument ( '-c' , '--color' )
namespace = parser . parse_args ()
command_line_args = { k : v for k , v in vars (namespace). items () if v }
combined = ChainMap (command_line_args, os.environ, defaults)
print (combined[ 'color' ])
print (combined[ 'user' ])
red
guest
使用 ChainMap
对象作为嵌套上下文
我们在上面提到了 new_child(m=None)
可用于创建子上下文,这个是一个非常便捷的方法,可以使用一个空字典或其他指定的映射来创建一个新的 ChainMap
对象。针对这个新对象的修改不会对原有的 ChainMap
对象(可以将其理解为底层的数据结构或者基础上下文)产生影响。
复制 >>> d_1 = { 'name' : 'bob' , 'age' : 25 }
>>> d_2 = { 'height' : '175' , 'weight' : 120 }
>>> c = ChainMap (d_1, d_2) # 创建一个基础上下文
>>> c_nc = c . new_child () # 创建一个嵌套的子上下文
>>> c_nc [ 'skill' ] = 'Python' # 在子上下文环境中进行赋值
>>> c
ChainMap ({ 'name' : 'bob' , 'age' : 25 }, { 'height' : '175' , 'weight' : 120 })
>>> c_nc
ChainMap ({ 'skill' : 'Python' }, { 'name' : 'bob' , 'age' : 25 }, { 'height' : '175' , 'weight' : 120 })
>>> list (c_nc)
[ 'height' , 'weight' , 'name' , 'age' , 'skill' ]
>>> dict (c_nc)
{ 'height' : '175' , 'weight' : 120 , 'name' : 'bob' , 'age' : 25 , 'skill' : 'Python' }
计数器Counter
Ps: Counter仅支持Hashable对象进行统计
定义
假如你有一长串没有标点符号或大写字母的单词,你想要计算每个单词出现的次数。
你可以使用字典或defaultdict增加计数,但collections.Counter提供了一种更清晰,更方便的方法。
Counter是dict的子类,它使用0作为任何缺失元素的默认值,并且更容易计算对象的出现次数:
复制 from collections import Counter
words = "if there was there was but if there was not there was not" . split ()
# 或者 counts = Counter(if=2,there=4,was=4,not=2,but=1) # 传进元组
counts = Counter (words)
print (counts)
>>> Counter ({ 'there' : 4 , 'was' : 4 , 'if' : 2 , 'not' : 2 , 'but' : 1 })
遍历元素
遍历所有元素
复制 # 当你将单词列表传递给Counter时,它会存储每个单词以及该单词在列表中出现的次数。
# 如果你好奇两个最常见的词是什么?只需使用.most_common():
print (counts. most_common ( 2 ))
# 遍历所有元素
for k , v in counts . items ():
print (k, v)
# 遍历打印所有元素
print ( sorted (counts. elements ()))
复制 [( 'there', 4), ('was', 4)]
if 2
there 4
was 4
but 1
not 2
[ 'but', 'if', 'if', 'not', 'not', 'there', 'there', 'there', 'there', 'was', 'was', 'was', 'was']
更新元素
复制 # update(增加元素)
counts . update ( "if you are here" . split ())
print (counts)
# subtract(原来的元素减去新传入的元素)
counts . subtract ([ 'if' ]) # if的次数减一
print (counts)
# 删除元素
counts [ 'but' ] = 0
del counts [ 'but' ]
print (counts)
复制 Counter ({ 'there': 4, 'was': 4, 'if': 3, 'not': 2, 'but': 1, 'you': 1, 'are': 1, 'here': 1})
Counter ({ 'there': 4, 'was': 4, 'if': 2, 'not': 2, 'but': 1, 'you': 1, 'are': 1, 'here': 1})
Counter ({ 'there': 4, 'was': 4, 'if': 2, 'not': 2, 'you': 1, 'are': 1, 'here': 1})
类集合操作
复制 c = Counter (a = 3 , b = 1 )
d = Counter (a = 1 , b = 2 )
print (c + d) # 相加
print (c - d) # 相减,如果小于等于0,删去
print (c & d) # 求最小
print (c | d) # 求最大
复制 Counter ({ 'a': 4, 'b': 3})
Counter ({ 'a': 2})
Counter ({ 'a': 1, 'b': 1})
Counter ({ 'a': 3, 'b': 2})
子类化UserDict
就创造自定义映射类型来说,以 UserDict
为基类,总比以普通的 dict
为基类要来得方便。
而更倾向于从 UserDict
而不是从 dict
继承的主要原因是,后者有时会在某些方法的实现上走一些捷径,导致我们不得不在它的子类中重写这些方法,但是 UserDict
就不会带来这些问题。
值得注意的地方是,UserDict
并不是 dict
的子类,但是 UserDict
有一个叫作 data
的属性,是 dict
的实例,这个属性实际上是 UserDict
最终存储数据的地方。
双向队列deque
定义
deque是栈和队列的一种广义实现,deque是"double-end queue"的简称;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。
常用方法
deque支持如下方法,
append(x), 将x添加到deque的右侧;
appendleft(x), 将x添加到deque的左侧;
clear(), 将deque中的元素全部删除,最后长度为0;
count(x), 返回deque中元素等于x的个数;
extend(iterable), 将可迭代变量iterable中的元素添加至deque的右侧;
extendleft(iterable), 将变量iterable中的元素添加至deque的左侧,往左侧添加序列的顺序与可迭代变量iterable中的元素相反;
pop(), 移除和返回deque中最右侧的元素,如果没有元素,将会报出IndexError;
popleft(), 移除和返回deque中最左侧的元素,如果没有元素,将会报出IndexError;
remove(value), 移除第一次出现的value,如果没有找到,报出ValueError;
reverse(), 反转deque中的元素,并返回None;
rotate(n), 从右侧反转n步,如果n为负数,则从左侧反转,d.rotate(1)等于d.appendleft(d.pop());
maxlen, 只读的属性,deque的最大长度,如果无解,就返回None;
除了以上的方法之外,deque还支持迭代、序列化、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d),通过in操作符进行成员测试和下标索引,索引的时间复杂度是在两端是O(1),在中间是O(n),为了快速获取,可以使用list代替。
index(查找某个元素的索引位置)
insert(在指定位置插入元素)
复制 >>> from collections import deque
>>> d = deque ( 'ghi' ) # 新建一个deque,有三个元素
>>> for ele in d : # 遍历deque
... print ele . upper ()
...
...
G
H
I
>>> d . append ( 'j' ) # deque右侧添加一个元素
>>> d . appendleft ( 'f' ) # deque左侧添加一个元素
>>> d # 打印deque
deque ([ 'f' , 'g' , 'h' , 'i' , 'j' ])
>>> d . pop () # 返回和移除最右侧元素
'j'
>>> d . popleft () # 返回和移除最左侧元素
'f'
>>> list (d) # 以列表形式展示出deque的内容
[ 'g' , 'h' , 'i' ]
>>> d [ 0 ] # 获取最左侧的元素
'g'
>>> d [ - 1 ] # 获取最右侧的元素
'i'
>>> list ( reversed (d)) # 以列表形式展示出倒序的deque的内容
[ 'i' , 'h' , 'g' ]
>>> 'h' in d # 在deque中搜索
True
>>> d . extend ( 'jkl' ) # 一次添加多个元素
>>> d
deque ([ 'g' , 'h' , 'i' , 'j' , 'k' , 'l' ])
>>> d . rotate ( 1 ) # 往右侧翻转
>>> d
deque ([ 'l' , 'g' , 'h' , 'i' , 'j' , 'k' ])
>>> d . rotate ( - 1 ) # 往左侧翻转
>>> d
deque ([ 'g' , 'h' , 'i' , 'j' , 'k' , 'l' ])
>>> deque ( reversed (d)) # 以逆序新建一个deque
deque ([ 'l' , 'k' , 'j' , 'i' , 'h' , 'g' ])
>>> d . clear () # 清空deque
>>> d . pop () # 不能在空的deque上pop
Traceback (most recent call last):
File "<input>" , line 1 , in < module >
IndexError : pop from an empty deque
>>> d . extendleft ( 'abc' ) # 以输入的逆序向左扩展
>>> d
deque ([ 'c' , 'b' , 'a' ])
复制 # deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
# 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
>>> from collections import deque
>>> q = deque ([ 'a' , 'b' , 'c' ])
>>> q . append ( 'x' )
>>> q . appendleft ( 'y' )
>>> q
deque ([ 'y' , 'a' , 'b' , 'c' , 'x' ])
# deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素
# deque是线程安全的,有GIL保护
# append和popleft都是原子操作
multiprocessing :这个包实现了自己的Queue,它和queue.Queue类似,是设计给进程间通信使用的。同时还有个multiprocessing.JoinableQueue类型,可以让任务管理变得更方便。
asyncio :python3.4新提供的包,里面有Queue、LifoQueue、PriorityQueue和JoinableQueue,这些类受到queue和mulitiprocessing模块的影响,但是为异步编程里的任务管理提供了便利。
子类化UserDict