Recently I saw this article about prime numbers and I liked the animation explaining how they are generated. But I didn't like the code that followed, so I decided to create my own version using ideas from the article.

```
def primes(upper_bound):
lower_bound = 2
lst = list(range(lower_bound, upper_bound))
lst_len = len(lst)
primes = []
while lower_bound < upper_bound:
primes.append(lower_bound)
lst = [el for el in lst if el % lower_bound != 0]
new_lst_len = len(lst)
if lst_len - new_lst_len > 1:
lst_len = new_lst_len
else:
primes.extend(lst)
return primes
lower_bound = lst[0]
```

Using an assertion showed that the two functions produce identical results. If we compare their performance with an upper bound of 10000, we'll see that Erathostenes is on average around 8 times faster than this function. Yet, sometimes speed isn't everything. The code must be easy to understand even for an average programmer. If it appears as a collection of hacks, specifically designed to increase performance, then this practice should be questioned and where possible abandoned. Minor speed improvements should never be preferred over readability and ease of understanding.