利用 .append
和 .pop
方法,我们可以把列表
当作栈
或者队列
来用(比如,把 .append
和 .pop(0)
合起来用,就能模拟栈的“先进先出”的特点)。但是删除列表的第一个元素(抑或是在第一个元素之前添加一个元素)之类的操作是很耗时的,因为这些操作会牵扯到移动列表里的所有元素。
collections.deque
类(双向队列)是一个线程安全
、可以快速
从两端
添加或者删除元素的数据类型。而且如果想要有一种数据类型来存放“最近用到的几个元素”,deque
也是一个很好的选择。这是因为在新建一个双向队列的时候,你可以指定这个队列的大小,如果这个队列满员了,还可以从反向端删除过期的元素,然后在尾端添加新的元素。下面示例中有几个双向队列的典型操作。
# -*- coding: utf-8 -*-
from collections import deque
# maxlen 是一个可选参数,代表这个队列可以容纳的元素的数量,而且一旦设定,这个属性就不能修改了。
dq = deque(range(10), maxlen=10)
print(dq)
# deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
# 队列的旋转操作接受一个参数 n,当 n > 0 时,队列的最右边的 n 个元素会被移动到队列的左边。
# 当 n < 0 时,最左边的 n 个元素会被移动到右边。
dq.rotate(3)
print(dq)
# deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
dq.rotate(-4)
print(dq)
# deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
# 当试图对一个已满(len(d) == d.maxlen)的队列做尾部添加操作的时候,它头部的元
# 素会被删除掉。注意在下一行里,元素 0 被删除了。
dq.appendleft(-1)
print(dq)
# deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
dq.extend([11, 22, 33]) # 在尾部添加 3 个元素的操作会挤掉 -1、1 和 2。
print(dq)
# deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
# extendleft(iter) 方法会把迭代器里的元素逐个添加到双向队列的左边,因此迭代器里的元素会逆序出现在队列里。
dq.extendleft([10, 20, 30, 40])
print(dq)
# deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
上面总结了列表和双向队列这两个类型的方法(object 类包含的方法除外)。
双向队列实现了大部分列表所拥有的方法,也有一些额外的符合自身设计的方法,比如说popleft
和 rotate
。但是为了实现这些方法,双向队列也付出了一些代价,从队列中间
删除元素的操作会慢一些,因为它只对在头尾
的操作进行了优化。
append
和 popleft
都是原子操作,也就说是 deque
可以在多线程
程序中安全地当作先进先出的栈使用,而使用者不需要担心资源锁的问题。
下面 列表和双向队列的方法(不包括由对象实现的方法)
a_list.pop(p)
这个操作只能用于列表,双向队列的这个方法不接收参数
除了 deque
之外,还有些其他的 Python
标准库也有对队列的实现。
-
queue
提供了同步(线程安全)类Queue
、LifoQueue
和PriorityQueue
,不同的线程可以利用这些数据类型来交换信息。这三个类的构造方法都有一个可选参数maxsize
,它接收正整数作为输入值,用来限定队列的大小。但是在满员的时候,这些类不会扔掉
旧的元素来腾出位置。相反,如果队列满了,它就会被锁住
,直到另外的线程移除了某个元素
而腾出了位置。这一特性让这些类很适合用来控制活跃线程
的数量。 -
multiprocessing
这个包实现了自己的Queue
,它跟queue.Queue
类似,是设计给进程间通信用的。同时还有一个专门的multiprocessing.JoinableQueue
类型,可以让任务管理变得更方便。 -
asyncio
Python 3.4
新提供的包,里面有Queue
、LifoQueue
、PriorityQueue
和JoinableQueue
,这些类受到queue
和multiprocessing
模块的影响,但是为异步编程里的任务管理提供了专门的便利。 -
heapq
跟上面三个模块不同的是,heapq
没有队列类,而是提供了heappush
和heappop
方法,让用户可以把可变序列当作堆队列或者优先队列来使用。