Skip to Content
Course content

231: Collections Module: deque

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Look, we've all been there. You need a simple queue—first in, first out—to handle some tasks or track a history of events, and your first instinct is to reach for a standard Python list. It's convenient, it's familiar, and for a few dozen items, it works perfectly. But as soon as you scale that logic to thousands of entries, you're going to hit a performance wall that isn't immediately obvious from the code itself.

The Hidden Cost of popping from the front

Imagine you're building a system to track the last 1,000 logs from a server. You use a list, append() new logs to the end, and when the list gets too long, you call logs.pop(0) to remove the oldest entry. On the surface, this looks clean. However, under the hood, Python lists are contiguous arrays. When you remove the element at index 0, every single remaining element in that list has to be shifted one position to the left to fill the gap.

# The naive way
logs = []
for i in range(100000):
    logs.append(f"Log entry {i}")
    if len(logs) > 1000:
        logs.pop(0)  # This is the silent killer

In computer science terms, pop(0) is an O(n) operation. If your list has 1,000 items, Python performs 999 shifts every time you remove the oldest log. If your list grows to 100,000, that's 99,999 shifts per removal. You'll notice your CPU spiking and your application lagging, and you'll be scratching your head because the logic seems so simple.

Why the deque is the right tool

This is exactly why the collections module gives us the deque (short for "double-ended queue"). Unlike a list, a deque is implemented as a doubly-linked list. This means adding or removing elements from either the beginning or the end happens in O(1) time. It doesn't matter if you have ten items or ten million; popping from the left is just as fast as popping from the right.

from collections import deque

# The professional way
logs = deque()
for i in range(100000):
    logs.append(f"Log entry {i}")
    if len(logs) > 1000:
        logs.popleft()  # Instantaneous, regardless of size

I want to point out popleft() specifically. That's the deque equivalent of pop(0), but without the baggage of shifting elements. If you're moving things from one end to the other, this is your go-to tool.

Handling fixed-size buffers automatically

Now, here is my favorite feature of the deque that most people overlook: the maxlen argument. In the previous examples, I manually checked the length of the collection and popped the old item. But if you know your buffer should only ever hold, say, 1,000 items, you can bake that constraint right into the object.

# No more manual length checks
logs = deque(maxlen=1000)
for i in range(100000):
    logs.append(f"Log entry {i}") 
    # When the 1001st item arrives, the 1st item is 
    # automatically discarded from the opposite end.

This isn't just cleaner code; it's more robust. You remove the risk of forgetting the if len(logs) > limit check in some other part of your app. When you need a "sliding window" of data, maxlen is the most elegant way to handle it in Python.




📋 Practical Task

Implementing a Fixed-Size Undo Buffer

You are building a simple text editor engine. To support an "Undo" feature, you need to keep track of the last 20 actions the user performed (e.g., "Typed 'A'", "Deleted Line 5", "Pasted Text"). If the user performs a 21st action, the oldest action should be forgotten automatically to save memory.

Your Task: Create a class called UndoManager. It should:

  • Initialize a deque with a maximum length of 20.
  • Have a method record_action(action_text) that adds a new action to the buffer.
  • Have a method undo() that removes and returns the most recent action from the buffer. If the buffer is empty, it should return None.
  • Have a method get_history() that returns the current buffer as a standard Python list.

Test your implementation by recording 25 different actions and verifying that only the last 20 remain in the history.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.