Skip to content

Commit 30bf1eb

Browse files
committed
Sample code for the article on deque
1 parent 961f910 commit 30bf1eb

File tree

10 files changed

+266
-0
lines changed

10 files changed

+266
-0
lines changed

python-deque/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Python's deque: Implement Efficient Queues and Stacks
2+
3+
This folder provides the code examples for the Real Python tutorial [Python's deque: Implement Efficient Queues and Stacks](https://realpython.com/python-deque/).

python-deque/custom_queue.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from collections import deque
2+
3+
4+
class Queue:
5+
def __init__(self):
6+
self._items = deque()
7+
8+
def enqueue(self, item):
9+
self._items.append(item)
10+
11+
def dequeue(self):
12+
try:
13+
return self._items.popleft()
14+
except IndexError:
15+
raise IndexError("dequeue from an empty queue") from None
16+
17+
def __len__(self):
18+
return len(self._items)
19+
20+
def __contains__(self, item):
21+
return item in self._items
22+
23+
def __str__(self):
24+
return f"Queue({list(self._items)})"
25+
26+
def __iter__(self):
27+
yield from self._items
28+
29+
def __reversed__(self):
30+
yield from reversed(self._items)

python-deque/page.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from collections import deque
2+
3+
doc_history = deque(maxlen=3)
4+
5+
urls = ("https://google.com", "https://yahoo.com", "https://www.bing.com")
6+
7+
for url in urls:
8+
doc_history.appendleft(url)
9+
10+
print(doc_history)
11+
12+
doc_history.appendleft("https://youtube.com")
13+
14+
print(doc_history)
15+
16+
doc_history.appendleft("https://facebook.com")
17+
18+
print(doc_history)

python-deque/producer_consumer.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import collections
2+
import logging
3+
import random
4+
import threading
5+
import time
6+
7+
logging.basicConfig(level=logging.INFO, format="%(threadName)s %(message)s")
8+
9+
10+
class SynchronizedBuffer:
11+
def __init__(self, capacity):
12+
self.values = collections.deque(maxlen=capacity)
13+
self.lock = threading.RLock()
14+
self.consumed = threading.Condition(self.lock)
15+
self.produced = threading.Condition(self.lock)
16+
17+
def __repr__(self):
18+
return repr(list(self.values))
19+
20+
@property
21+
def empty(self):
22+
return len(self.values) == 0
23+
24+
@property
25+
def full(self):
26+
return len(self.values) == self.values.maxlen
27+
28+
def put(self, value):
29+
with self.lock:
30+
self.consumed.wait_for(lambda: not self.full)
31+
self.values.append(value)
32+
self.produced.notify()
33+
34+
def get(self):
35+
with self.lock:
36+
self.produced.wait_for(lambda: not self.empty)
37+
try:
38+
return self.values.popleft()
39+
finally:
40+
self.consumed.notify()
41+
42+
43+
def producer(buffer):
44+
while True:
45+
value = random.randint(1, 10)
46+
buffer.put(value)
47+
logging.info("produced %d: %s", value, buffer)
48+
time.sleep(random.random())
49+
50+
51+
def consumer(buffer):
52+
while True:
53+
value = buffer.get()
54+
logging.info("consumed %d: %s", value, buffer)
55+
time.sleep(random.random())
56+
57+
58+
if __name__ == "__main__":
59+
60+
buffer = SynchronizedBuffer(5)
61+
62+
for _ in range(3):
63+
threading.Thread(target=producer, args=(buffer,)).start()
64+
65+
for _ in range(2):
66+
threading.Thread(target=consumer, args=(buffer,)).start()

python-deque/rotate.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from collections import deque
2+
3+
4+
def slice_deque(deck, *, start, stop):
5+
slice = deque()
6+
temp = deque()
7+
for i in range(stop, start, -1):
8+
deck.rotate(i)
9+
item = deck.popleft()
10+
slice.appendleft(item)
11+
temp.append(item)
12+
deck.extend(temp)
13+
# for i in range(start, stop):
14+
# deck.rotate(-i)
15+
16+
return slice
17+
18+
19+
d = deque([1, 2, 3, 4, 5])
20+
print(slice_deque(d, start=0, stop=3))
21+
print(d)

python-deque/tail.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from collections import deque
2+
3+
4+
def tail(filename, lines=10):
5+
try:
6+
with open(filename) as file:
7+
return deque(file, lines)
8+
except OSError as error:
9+
print(f'Opening file "{filename}" failed with error: {error}')

python-deque/threads.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import logging
2+
import random
3+
import threading
4+
import time
5+
from collections import deque
6+
7+
logging.basicConfig(level=logging.INFO, format="%(message)s")
8+
9+
10+
def wait_seconds(mins, maxs):
11+
time.sleep(mins + random.random() * (maxs - mins))
12+
13+
14+
def produce(queue, size):
15+
while True:
16+
if len(queue) < size:
17+
value = random.randint(0, 9)
18+
queue.append(value)
19+
logging.info("Produced: %d -> %s", value, str(queue))
20+
else:
21+
logging.info("Queue is saturated")
22+
wait_seconds(0.1, 0.5)
23+
24+
25+
def consume(queue):
26+
while True:
27+
try:
28+
value = queue.popleft()
29+
except IndexError:
30+
logging.info("Queue is empty")
31+
else:
32+
logging.info("Consumed: %d -> %s", value, str(queue))
33+
wait_seconds(0.2, 0.7)
34+
35+
36+
logging.info("Starting Threads...\n")
37+
logging.info("Press Ctrl+C to interrupt the execution\n")
38+
39+
shared_queue = deque()
40+
41+
threading.Thread(target=produce, args=(shared_queue, 10)).start()
42+
threading.Thread(target=consume, args=(shared_queue,)).start()

python-deque/time_append.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from collections import deque
2+
from time import perf_counter
3+
4+
TIMES = 10_000
5+
a_list = []
6+
a_deque = deque()
7+
8+
9+
def average_time(func, times):
10+
total = 0.0
11+
for i in range(times):
12+
start = perf_counter()
13+
func(i)
14+
total += (perf_counter() - start) * 1e9
15+
return total / times
16+
17+
18+
list_time = average_time(lambda i: a_list.insert(0, i), TIMES)
19+
deque_time = average_time(lambda i: a_deque.appendleft(i), TIMES)
20+
gain = list_time / deque_time
21+
22+
print(f"list.insert() {list_time:.6} ns")
23+
print(f"deque.appendleft() {deque_time:.6} ns ({gain:.6}x faster)")

python-deque/time_pop.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from collections import deque
2+
from time import perf_counter
3+
4+
TIMES = 10000
5+
a_list = [1] * TIMES
6+
a_deque = deque(a_list)
7+
8+
9+
def average_time(func, times):
10+
total = 0.0
11+
for _ in range(times):
12+
start = perf_counter()
13+
func()
14+
total += (perf_counter() - start) * 1e9
15+
return total / times
16+
17+
18+
list_time = average_time(lambda: a_list.pop(0), TIMES)
19+
deque_time = average_time(lambda: a_deque.popleft(), TIMES)
20+
gain = list_time / deque_time
21+
22+
print(f"list.pop() {list_time:.6} ns")
23+
print(f"deque.popleft() {deque_time:.6} ns ({gain:.6}x faster)")

python-deque/time_random_access.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from collections import deque
2+
from time import perf_counter
3+
4+
TIMES = 10_000
5+
a_list = [1] * TIMES
6+
a_deque = deque(a_list)
7+
8+
9+
def average_time(func, times):
10+
total = 0.0
11+
for _ in range(times):
12+
start = perf_counter()
13+
func()
14+
total += (perf_counter() - start) * 1e6
15+
return total / times
16+
17+
18+
def time_it(sequence):
19+
middle = len(sequence) // 2
20+
sequence.insert(middle, "middle")
21+
sequence[middle]
22+
sequence.remove("middle")
23+
del sequence[middle]
24+
25+
26+
list_time = average_time(lambda: time_it(a_list), TIMES)
27+
deque_time = average_time(lambda: time_it(a_deque), TIMES)
28+
gain = deque_time / list_time
29+
30+
print(f"list {list_time:.6} μs ({gain:.6}x faster)")
31+
print(f"deque {deque_time:.6} μs")

0 commit comments

Comments
 (0)