from collections import deque, namedtuple HistoryItem = namedtuple("HistoryItem", ["timestamp", "data"]) def process(data): pass class HistoryQueue: def __init__(self): self.hist = deque() def log_new(self, timestamp, data): item = HistoryItem(timestamp, data) self.hist.append(item) # Will IndexError out if self.hist gets empty, BAD def clear_old_1(self, now): while (now-self.hist[0].timestamp).total_seconds() >= 60: first_item = self.hist.popleft() process(first_item.data) # Will inadvertently catch possible IndexErrors in process(), making debugging painful, BAD def clear_old_2(self, now): try: while (now-self.hist[0].timestamp).total_seconds() >= 60: first_item = self.hist.popleft() process(first_item.data) except IndexError: pass # Will work as intended, uses try/except, and each individual portion of the code is readable and adheres to python best-practices, but together it looks like a giant mess with convoluted branching, hindering readability. Okay, but not great. Also, re-use name "first_item" def clear_old_3(self, now): while True: try: first_item = self.hist[0].timestamp except IndexError: break else: if (now - first_event.timestamp).total_seconds() < 60: break else: first_item = self.hist.popleft() # or just self.hist.popleft() and use first_item from before process(first_item.data) # A lot more readable, perhaps best, but is there a way to avoid LBYL? Also feels kind of hacky to put in that "len(self.hist) >= 1" in the start of the while expression to avoid IndexErrors in the second half, but perhaps this is indeed the best? def clear_old_4(self, now): while len(self.hist) >= 1 and (now - self.hist[0].timestamp) >= 60: first_item = sell.hist.popleft() process(first_item.data)