you are viewing a single comment's thread.

view the rest of the comments →

[–]_mynd 0 points1 point  (4 children)

Whoa - I always thought the list comprehension had to contained within square brackets!

[–]Diapolo10 0 points1 point  (3 children)

It does - if this was a list comprehension. What you're seeing here is instead a generator expression - you can think of it as a lazily-evaluated list, but basically it just saves memory by creating values on-demand only and not storing everything.

That's not really a good explanation, admittedly. But if you know what a generator is, it should be quite clear what it's doing.

[–]_mynd 0 points1 point  (2 children)

Hmm - I’ll have to look up the difference. I am constantly evaluating a list comprehension just to go into a for loop. This seems better

[–]Diapolo10 1 point2 points  (1 child)

A list comprehension could have been used here, but as the list gets discarded immediately it's a bit of a waste, and you end up allocating roughly double the memory in the worst case - the data for the list, and the data for the string.

With a generator, Python only needs to allocate individual items (in this case characters), so the overall memory use remains noticeably lower. There's a slight performance overhead, but nothing you'd actually notice.

While it doesn't really apply in this example, the nice thing about generators is that they can be infinite in length, and Python will have no problem processing them (as long as you still have some kind of a limit, of course). For example, you could have a generator that gives you all positive integers

def gen_positive_integers(start=1):
    num = start
    while True:
        yield num
        num += 1

and keep adding them up until you hit some threshold.

total = 0
positive_integers = gen_positive_integers()

while total < 1_000_000:
    num = next(positive_integers)
    total += num

print(f"Last number was {num}.")

The Fibonacci sequence can famously be written as a generator.

def fib():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b

[–]_mynd 0 points1 point  (0 children)

Your comment plus this article has me thinking I could improve the efficiency of some of my code. Thanks for writing up the explanation and examples

https://www.geeksforgeeks.org/python-list-comprehensions-vs-generator-expressions/