To keep the last N items of a collection in Python, we slice it with [-n:], and to keep the last N items of a stream that keeps growing, we use collections.deque(maxlen=n), which drops the oldest item when the deque is full. Slicing works the same way for lists, strings and NumPy arrays.
| Approach / Data Type | When to Use? | Example |
|---|---|---|
| deque | Elements arrive one at a time, in a loop | q = deque(maxlen=3) and q.append(item) |
| list | The whole list is already in memory | last_n = my_list[-3:] |
| NumPy array | Numerical data and large datasets | last_n = my_array[-3:] |
| string | Text such as the end of a log line | last_n_chars = my_string[-3:] |
This tutorial explores each method with examples, adds the last lines of a file and a moving average, and shows the n = 0 trap of negative slicing. The examples run on Python 3.14 with NumPy 2.5.
1. Keeping Last N Items using deque
The deque (double-ended queue) allows fast appends and pops at both ends. With maxlen, it keeps at most that many items, and appending to a full deque removes the item at the other end.
from collections import deque
q = deque(maxlen=3)
for n in [1, 2, 3, 4, 5]:
q.append(n)
last_three = list(q) # [3, 4, 5]
size = q.maxlen # 3
A deque with maxlen never grows beyond its limit, so it is the right tool for “the last N events” in a long-running loop. It does not support slicing, so we convert it with list(q) when we need a slice.
2. Finding Last N Items from a List
Python lists have no maximum length, but slicing with a negative start returns the last N elements as a new list. A slice longer than the list returns the whole list, without an error.
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
last_n_items_list = my_list[-3:] # [7, 8, 9]
more_than_len = my_list[-20:] # the whole list
Negative slicing has one trap. For n = 0, my_list[-0:] equals my_list[0:] and returns the whole list instead of an empty one, so a helper should handle zero explicitly.
def last_n(seq, n):
return seq[-n:] if n > 0 else seq[:0]
zero_wrong = my_list[-0:] # [1, 2, ... 9], the whole list
zero_right = last_n(my_list, 0) # []
3. Finding Last N Items from NumPy Arrays
For numerical data, NumPy arrays support the same slicing. The result is a view that shares memory with the original array, so changing it changes the original too; .copy() makes it independent.
import numpy as np
my_array = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
last_n_items_array = my_array[-3:] # array([7, 8, 9])
independent = my_array[-3:].copy()
4. Finding Last N Characters of a String
Strings are sequences too, so [-n:] returns the last N characters. It works for file extensions of fixed length, masked card numbers or the end of a long log line.
card = "4111111111111234"
masked = "*" * 12 + card[-4:] # '************1234'
5. Reading the Last Lines of a File
A file object yields its lines one by one, and a deque with maxlen keeps only the last N of them. That reads a log file of any size with constant memory, like the Unix tail command.
def tail(path, n=3):
with open(path, encoding="utf-8") as f:
return [line.rstrip("\n") for line in deque(f, maxlen=n)]
last_lines = tail("app.log", 2) # ['INFO saved order 7', 'ERROR payment timeout']
The file app.log in the example holds five lines, from INFO start to ERROR payment timeout, and only the last two remain in the deque.
6. A Moving Average over the Last N Readings
Sensor data often needs an average of the latest readings. The deque keeps the window, and the average is calculated from it after each new value.
window = deque(maxlen=3)
averages = []
for reading in [10, 20, 30, 40, 50]:
window.append(reading)
averages.append(sum(window) / len(window))
# averages = [10.0, 15.0, 20.0, 30.0, 40.0]
7. Last N Items FAQs
Generators, the first N items and threads need slightly different tools.
7.1. How do we get the last N items of a generator?
A generator cannot be sliced, but deque(generator, maxlen=n) consumes it and keeps the last N items. The generator must be finite.
7.2. How do we keep the first N items instead?
We slice with [:n], which also works for n = 0. For iterators, itertools.islice(it, n) takes the first N items without reading the rest.
7.3. Is a deque thread-safe?
In CPython, append() and popleft() are atomic, so producers and consumers can share a deque. For more complex coordination, queue.Queue adds blocking and limits.
8. Conclusion
Slicing with [-n:] returns the last N items of a list, string or NumPy array, with a check for n = 0. For data that arrives over time, such as log lines or sensor readings, deque(maxlen=n) keeps the latest items in constant memory.
9. References
Happy Learning !!