deque & Queues

Reviewed & published by Brayan K

A deque (pronounced "deck") is a double-ended queue from the collections module that adds and removes items from both ends in fast O(1) time, making it the ideal tool for queues, stacks, sliding windows, and fixed-size history buffers.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Lists are great, but removing from the front of a long list is painfully slow. A deque fixes that and unlocks elegant queue and buffer patterns.

What You'll Learn in This Lesson

1 Both Ends Are Fast

A deque gives you four push/pop methods: append and pop on the right (like a list), plus appendleft and popleft on the left. All four are O(1):

from collections import deque

d = deque([1, 2, 3])

d.append(4)        # add to the right
d.appendleft(0)    # add to the left
print(d)           # deque([0, 1, 2, 3, 4])

print(d.pop())      # 4  (remove from the right)
print(d.popleft())  # 0  (remove from the left)
print(d)            # deque([1, 2, 3])

# extend works on both ends too
d.extendleft([0, -1])   # note: each item is pushed to the left
print(d)                # deque([-1, 0, 1, 2, 3])
from collections import deque

# A deque can act as a simple browser history
history = deque()
history.append("home")
history.append("about")
history.append("pricing")

# Go back: pop from the right
print("Now on:", history[-1])
history.pop()
print("Back to:", history[-1])

# ✅ Expected output:
# Now on: pricing
# Back to: about

2 A Proper FIFO Queue

A queue is "first in, first out": the first person in line is served first. With a deque you append new arrivals on the right and popleft the next to serve — both O(1):

from collections import deque

queue = deque()
queue.append("Ada")     # Ada joins the line
queue.append("Ben")
queue.append("Cleo")

# Serve in arrival order
print(queue.popleft())  # Ada
print(queue.popleft())  # Ben
print(queue)            # deque(['Cleo'])

# Why not a list? list.pop(0) is O(n):
# every remaining element shifts down — slow for big queues.
# deque.popleft() is O(1) no matter the size.

For a small list the difference is invisible, but a queue with hundreds of thousands of items processed in a loop can be hundreds of times slower with list.pop(0) than with deque.popleft().

3 Ring Buffers with maxlen & rotate()

Give a deque a maxlen and it becomes a fixed-size ring buffer: once full, every new item pushes the oldest one out automatically. And rotate(n) shifts every element n places, wrapping around:

from collections import deque

# Keep only the last 3 readings
recent = deque(maxlen=3)
for reading in [10, 20, 30, 40, 50]:
    recent.append(reading)
    print(list(recent))
# [10]
# [10, 20]
# [10, 20, 30]
# [20, 30, 40]   <- 10 fell off the left
# [30, 40, 50]   <- 20 fell off the left

# rotate(1) moves everything right by 1, wrapping the end to the front
letters = deque(["a", "b", "c", "d"])
letters.rotate(1)
print(letters)          # deque(['d', 'a', 'b', 'c'])
letters.rotate(-2)      # negative rotates left
print(letters)          # deque(['b', 'c', 'd', 'a'])
from collections import deque

# Rolling average of the last 3 temperatures
window = deque(maxlen=3)
temps = [20, 22, 24, 26, 28]

for t in temps:
    window.append(t)
    avg = sum(window) / len(window)
    print(f"After {t}: window={list(window)}, avg={avg:.1f}")

# ✅ Expected output:
# After 20: window=[20], avg=20.0
# After 22: window=[20, 22], avg=21.0
# After 24: window=[20, 22, 24], avg=22.0
# After 26: window=[22, 24, 26], avg=24.0
# After 28: window=[24, 26, 28], avg=26.0

🎯 Your Turn: Fill in the Blanks

Replace each ___ so the print jobs are processed in arrival order (FIFO).

# 🎯 YOUR TURN: process a print queue first-in-first-out
from collections import ___

jobs = deque()
jobs.append("report.pdf")
jobs.append("photo.png")
jobs.append("notes.txt")

while jobs:
    nxt = jobs.___()    # take the OLDEST job (left side)
    print("Printing:", nxt)

# Expected output:
# Printing: report.pdf
# Printing: photo.png
# Printing: notes.txt

Common Errors

❌ Using list.pop(0) for a big queue

q = list(range(1000000))
while q:
    q.pop(0)   # O(n) each time — extremely slow

✅ Use a deque for O(1) popleft

from collections import deque
q = deque(range(1000000))
while q:
    q.popleft()   # O(1) each time

❌ Indexing the middle of a deque in a tight loop

d[len(d) // 2]   # O(n) — deques are slow in the middle

✅ Use a list when you need random access

data = [...]      # lists give O(1) indexing anywhere

❌ Forgetting extendleft reverses order

d = deque([3])
d.extendleft([1, 2])
print(d)   # deque([2, 1, 3]) — not [1, 2, 3]!

✅ Reverse first, or append one by one

d = deque([3])
d.extendleft(reversed([1, 2]))
print(d)   # deque([1, 2, 3])

🎯 Mini Challenge: Palindrome Checker

A deque is perfect for checking palindromes: compare the two ends, then chop them off and repeat.

# 🎯 Mini Challenge: is the word a palindrome?
from collections import deque

def is_palindrome(word):
    d = deque(word)
    while len(d) > 1:
        if d.popleft() != d.pop():   # compare both ends
            return False
    return True

for w in ["racecar", "level", "python", "noon"]:
    print(w, "->", is_palindrome(w))

# Expected output:
# racecar -> True
# level -> True
# python -> False
# noon -> True

📚 Keep Learning

Frequently Asked Questions

Lesson complete — you wield queues like a pro!

You can build O(1) queues and stacks with append/popleft, keep a rolling window with maxlen, shift elements with rotate(), and you know exactly when a plain list is the better choice.

Practice quiz

Which collections type gives O(1) appends and pops at BOTH ends?

  • list
  • tuple
  • deque
  • set

Answer: deque. A deque (double-ended queue) is optimized so appendleft/popleft and append/pop are all O(1).

To use a deque as a FIFO queue, you append on the right and remove with which method?

  • popleft()
  • pop()
  • remove()
  • pop(0)

Answer: popleft(). FIFO means removing the oldest item: append() adds on the right and popleft() removes from the left in O(1).

After deque(maxlen=3) receives 10, 20, 30, 40, 50 via append(), what does list() show?

  • [10, 20, 30]
  • [10, 20, 30, 40, 50]
  • [20, 30, 40]
  • [30, 40, 50]

Answer: [30, 40, 50]. A maxlen deque drops the oldest item from the left each time it overflows, leaving the last three: 30, 40, 50.

Given d = deque([3]) then d.extendleft([1, 2]), what is d?

  • deque([1, 2, 3])
  • deque([2, 1, 3])
  • deque([3, 1, 2])
  • deque([3, 2, 1])

Answer: deque([2, 1, 3]). extendleft appends each item to the left one at a time, so the order is reversed: 2, 1, 3.

Why is deque.popleft() far faster than list.pop(0) for a large queue?

  • list.pop(0) is O(n) because every remaining element shifts down, while popleft() is O(1)
  • pop(0) is not allowed on lists
  • They are the same speed
  • deque uses less memory only

Answer: list.pop(0) is O(n) because every remaining element shifts down, while popleft() is O(1). Removing the first list element shifts all others down (O(n)); a deque's linked-block structure makes popleft O(1).

deque(['a','b','c','d']).rotate(1) produces which result?

  • deque(['b','c','d','a'])
  • deque(['a','b','c','d'])
  • deque(['d','a','b','c'])
  • deque(['c','d','a','b'])

Answer: deque(['d','a','b','c']). rotate(1) shifts everything right by one, wrapping the last element to the front: d, a, b, c.

What does a negative argument to rotate(), like rotate(-2), do?

  • Raises an error
  • Rotates the elements to the left
  • Reverses the deque
  • Clears the deque

Answer: Rotates the elements to the left. A negative count rotates left; rotate(-2) moves each element two places toward the front, wrapping around.

When you append to a full maxlen deque, the dropped item is...

  • Returned to you
  • Saved to a backup list
  • Raised as an exception
  • Silently discarded with no error or warning

Answer: Silently discarded with no error or warning. maxlen silently drops the item at the opposite end; if you need it you must capture it before it falls off.

For repeatedly indexing the MIDDLE element in a tight loop, which is the better choice?

  • deque, it is O(1) in the middle
  • list, because indexing the middle of a deque is O(n)
  • Either, both are O(1)
  • set, for fast lookup

Answer: list, because indexing the middle of a deque is O(n). Deques are slow (O(n)) for middle access; a list gives O(1) random indexing anywhere.

In the palindrome checker, which pair of methods compares the two ends of the deque?

  • append() and pop()
  • appendleft() and append()
  • popleft() and pop()
  • rotate() and pop()

Answer: popleft() and pop(). popleft() takes the leftmost char and pop() the rightmost, so comparing them checks the outer pair each iteration.

Continue this course

Frequently asked questions

What is a deque and how do you say it?

A deque (pronounced 'deck') is a double-ended queue from the collections module. It behaves like a list but is optimized so that adding or removing items at BOTH ends is fast — O(1). It's the right tool for queues, sliding windows, and undo histories where you push and pop from either side.

Why is deque faster than a list for queues?

Removing the first element of a list with pop(0) is O(n) because every remaining element must shift down one slot. A deque uses a doubly-linked block structure, so popleft() and appendleft() are O(1) no matter how big it gets. For a queue with thousands of items, that's a massive difference.

What does maxlen do?

Passing maxlen turns a deque into a fixed-size ring buffer. Once it's full, every new item you append automatically drops the item at the opposite end. It's perfect for keeping 'the last N events', a rolling average window, or a recent-history list — you never have to trim it yourself.

Should I always use deque instead of a list?

No. A list is still better for random access by index and for general-purpose storage, and indexing the middle of a deque is O(n). Choose deque specifically when your hot path is adding or removing at the ends — queues, stacks used heavily, and sliding windows. Use a list for everything else.