python:deque 对象

  • deque 用法


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

Deque队列是由栈或者queue队列生成的(发音是 “deck”,”double-ended queue”的简称)。Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。

虽然 list 对象也支持类似操作,不过这里优化了定长操作和 pop(0) 和 insert(0, v) 的开销。它们引起 O(n) 内存移动的操作,改变底层数据表达的大小和位置。

如果 maxlen 没有指定或者是 None ,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filter tail 的功能。它们同样可以用与追踪最近的交换和其他数据池活动。

双向队列(deque)对象支持以下方法:

append(x)
添加 x 到右端。

appendleft(x)
添加 x 到左端。

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

copy()
创建一份浅拷贝。

3.5 新版功能.

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

3.2 新版功能.

extend(iterable)
扩展deque的右侧,通过添加iterable参数中的元素。

extendleft(iterable)
扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

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

3.5 新版功能.

insert(i, x)
在位置 i 插入 x 。

如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。

3.5 新版功能.

pop()
移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。

popleft()
移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。

remove(value)
移除找到的第一个 value。 如果没有的话就引发 ValueError。

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

3.2 新版功能.

rotate(n=1)
向右循环移动 n 步。 如果 n 是负数,就向左循环。

如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。

Deque对象同样提供了一个只读属性:

maxlen
Deque的最大尺寸,如果没有限定的话就是 None 。

3.1 新版功能.

除了以上操作,deque 还支持迭代、封存、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d)、成员检测运算符 in 以及下标引用例如通过 d[0] 访问首个元素等。 索引访问在两端的复杂度均为 O(1) 但在中间则会低至 O(n)。 如需快速随机访问,请改用列表。

Deque从版本3.5开始支持 add(), mul(), 和 imul() 。

示例:

>>>
from collections import deque
d = deque('ghi')                 # make a new deque with three items
for elem in d:                   # iterate over the deque's elements
    print(elem.upper())
G
H
I

d.append('j')                    # add a new entry to the right side
d.appendleft('f')                # add a new entry to the left side
d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])

d.pop()                          # return and remove the rightmost item
'j'
d.popleft()                      # return and remove the leftmost item
'f'
list(d)                          # list the contents of the deque
['g', 'h', 'i']
d[0]                             # peek at leftmost item
'g'
d[-1]                            # peek at rightmost item
'i'

list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
'h' in d                         # search the deque
True
d.extend('jkl')                  # add multiple elements at once
d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
d.rotate(1)                      # right rotation
d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
d.rotate(-1)                     # left rotation
d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
d.clear()                        # empty the deque
d.pop()                          # cannot pop from an empty deque
Traceback (most recent call last):
    File "<pyshell#6>", line 1, in -toplevel-
        d.pop()
IndexError: pop from an empty deque

d.extendleft('abc')              # extendleft() reverses the input order
d
deque(['c', 'b', 'a'])

deque 用法

这一节展示了deque的多种用法。

限长deque提供了类似Unix tail 过滤功能

def tail(filename, n=10):
    'Return the last n lines of a 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
    # https://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

一个 轮询调度器 可以通过在 deque 中放入迭代器来实现。值从当前迭代器的位置0被取出并暂存(yield)。 如果这个迭代器消耗完毕,就用 popleft() 将其从对列中移去;否则,就通过 rotate() 将它移到队列的末尾

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

rotate() 方法提供了一种方式来实现 deque 切片和删除。 例如, 一个纯的Python del d[n] 实现依赖于 rotate() 来定位要弹出的元素

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

要实现 deque 切片, 使用一个类似的方法,应用 rotate() 将目标元素放到左边。通过 popleft() 移去老的条目(entries),通过 extend() 添加新的条目, 然后反向 rotate。这个方法可以最小代价实现命令式的栈操作,诸如 dup, drop, swap, over, pick, rot, 和 roll 。