Python Tutorial
Queues
A First-In-First-Out (FIFO) structure: items leave in the same order they arrived.
The FIFO Principle
A queue is a line at a ticket counter: you join at the rear (enqueue) and are served from the front (dequeue). The first to arrive is the first to leave — First In, First Out.
Queues model task scheduling, print spoolers, message buffers, and breadth-first search.
Why Not a Plain List?
You can use a list, but removing from the front (pop(0)) shifts every remaining element — O(n). For an efficient queue use collections.deque, which pops from both ends in O(1).
from collections import deque
queue = deque()
queue.append("A") # enqueue at rear
queue.append("B")
queue.append("C") # deque(['A', 'B', 'C'])
print(queue.popleft()) # 'A' -> dequeue from front, O(1)
print(queue[0]) # 'B' -> peek front
print(len(queue)) # 2A Reusable Queue Class
from collections import deque
class Queue:
def __init__(self):
self._items = deque()
def enqueue(self, value):
self._items.append(value)
def dequeue(self):
if self.is_empty():
raise IndexError("dequeue from empty queue")
return self._items.popleft()
def peek(self):
return self._items[0]
def is_empty(self):
return len(self._items) == 0
def size(self):
return len(self._items)
q = Queue()
q.enqueue(1); q.enqueue(2)
print(q.dequeue(), q.peek()) # 1 2Variants
- Deque (double-ended queue): add/remove at both ends —
append,appendleft,pop,popleft. - Circular queue: a fixed-size buffer that reuses freed slots (great for streaming).
- Priority queue: items leave by priority, not arrival — use
heapq.
import heapq
pq = []
heapq.heappush(pq, (2, "medium"))
heapq.heappush(pq, (1, "high"))
heapq.heappush(pq, (3, "low"))
print(heapq.heappop(pq)) # (1, 'high') -> smallest priority firstThread-Safe Queues
For producer/consumer threads, use queue.Queue, which handles locking internally.
from queue import Queue
q = Queue(maxsize=10)
q.put("job1") # blocks if full
print(q.get()) # 'job1'; blocks if empty
q.task_done()Best Practices
- Use
dequefor general queues — O(1) at both ends. - Avoid
list.pop(0); it is O(n). - Use
heapqfor priority queues andqueue.Queueacross threads. - Queues drive breadth-first search; stacks drive depth-first search.
Try It Yourself
Exercise 1: Simulate a print queue: enqueue 3 jobs, then process them in order.
Show solution
from collections import deque
q = deque()
for job in ["doc1", "doc2", "doc3"]:
q.append(job)
while q:
print("printing", q.popleft())Exercise 2: Why is deque better than a list for a queue?
Show solution
deque.popleft() is O(1), while list.pop(0) is O(n) because it shifts every element.
📘 Real-World Deep Dive
Knowing <strong>DSA Queues (algorithms & data structures)</strong> well is what turns algorithms & data structures from a curiosity into a daily tool — you'll reach for it in nearly every real project.
Real-Life Scenario
An end-to-end usage of DSA Queues that you'd actually see in a data pipeline or analytics notebook.
Real-Life Example
from collections import deque
jobs = deque()
jobs.append(("send-mail", 1))
jobs.append(("render", 3))
while jobs:
name, prio = jobs.popleft()
print(f"do {name} (prio {prio})")Expected Output
(see source)Common mistakes
- Off-by-one errors in binary-search: the standard idiom is
while lo <= hiwithmid = (lo + hi) // 2. - Recursive algorithms blow the stack for n > ~10⁴; convert to iterative with an explicit stack.
- Comparison algorithms (
sorted(iterable)) are stable by default in Python — surprising for Java/C++ users. - Treating DSA Queues as a black box without reading the docs — the API has subtle defaults that bite when you scale.
🚀 Performance & Best Practices
- Use
bisect.bisect_left/bisect_rightinstead of writing your own binary search. - Convert a sorted search into a tuple-access pattern with
numpy.searchsortedfor huge arrays. - Use
heapqfor priority queues instead of maintaining a sorted list manually. - When working with algorithms & data structures, prefer vectorised / batched operations over Python loops.
🧪 Try It Yourself
- Reproduce the snippet on a representative slice of your own data.
- Profile the snippet with
cProfileortimeitand find the single biggest improvement. - Generalise the snippet into a small, reusable function you can drop into future projects.