8

I often find it cleaner to write a generator than to return a list. For example, I prefer

def my_func_gen(foo):
    for i in foo:
        # Do some stuff that's too complicated for a list or generator comprehension
        yield whatever

to

def my_func_list(foo):
    result = []
    for i in foo:
        # Do some stuff that's too complicated for a list or generator comprehension
        result.append(whatever)
    return result

Further, this answer says, "You're encouraged to use iterators for everything." So is my_func_gen better, then? Maybe not. I'd like for the caller not to even know whether it's getting a list or an iterator. But the caller has to think about it because, for example, the iterator won't be sliceable using Python's nice clean syntax; I'll have to use itertools.islice.

So what should I do?

  1. Ignore the advice to "use iterators for everything"
  2. Get out of the habit of using slices and other behavior that's not available to all iterables
  3. Run list(my_iterable) any time I might want to use features that lists support and generators do not
  4. Use lists sometimes and generators others. But when?

Related: here's some code that users a wrapper class to make any iterator sliceable. It doesn't work quite the way you might think, though: looking up foo[:2] and then looking up foo[:2] again gives different results.

0

1 Answer 1

7

You are confused between generators and iterators. They are not the same concept at all.

Iterators are great and ubiquitous in Python. You should use them a lot. Both my_func_gen and my_func_list use them.

Generators are a lazy way to build iterables. They are useful when the fully realized list would not fit in memory, or when the cost to calculate each list element is high and you want to do it as late as possible. But they can only be iterated over once.

I invite you to go through this.

Not the answer you're looking for? Browse other questions tagged or ask your own question.