62

Suppose I have a list that I wish not to return but to yield values from. What is the most pythonic way to do that?

Here is what I mean. Thanks to some non-lazy computation I have computed the list ['a', 'b', 'c', 'd'], but my code through the project uses lazy computation, so I'd like to yield values from my function instead of returning the whole list.

I currently wrote it as following:

my_list = ['a', 'b', 'c', 'd']
for item in my_list:
    yield item

But this doesn't feel pythonic to me.

Mel
  • 5,837
  • 10
  • 37
  • 42
bodacydo
  • 75,521
  • 93
  • 229
  • 319
  • 3
    Why do you need to do that, you can use "for x in container" where container is a list or container is an iterator... the syntax doesn't change regardless of the type, so why does it matter whether it is a list or an iterator? You are still going to have to hang onto the list to yield from it, so simply pass around the list. – Michael Aaron Safyan Mar 23 '10 at 08:21
  • Side remark: with "List", many people will think of it as a class name because of the leading uppercase (see PEP 8). You could use "list_", or "my_list", etc. – Eric O. Lebigot Mar 23 '10 at 09:31
  • EOL, I appreciate your remark. Thanks. – bodacydo Mar 23 '10 at 10:01
  • An iterable can be thought of its own generator. That is, if I can write `for i in my_iterable:` that walks like a generator and quacks like a generator. – msw Sep 04 '13 at 18:13

3 Answers3

93

Since this question doesn't specify; I'll provide an answer that applies in Python >= 3.3

If you need only to return that list, do as Anurag suggests, but if for some reason the function in question really needs to be a generator, you can delegate to another generator; suppose you want to suffix the result list, but only if the list is first exhausted.

def foo():
    list_ = ['a', 'b', 'c', 'd']
    yield from list_

    if something:
        yield this
        yield that
        yield something_else

In versions of python prior to 3.3, though, you cannot use this syntax; you'll have to use the code as in the question, with a for loop and single yield statement in the body.

Alternatively; you can wrap the generators in a regular function and return the chained result: This also has the advantage of working in python 2 and 3

from itertools import chain

def foo():
    list_ = ['a', 'b', 'c', 'd']

    def _foo_suffix():
        if something:
            yield this
            yield that
            yield something_else

    return chain(list_, _foo_suffix())
Community
  • 1
  • 1
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 32
    The `yield from list_` feature is a nice syntax, and is what I came here looking for. Shame I can't use it in 2.7. – Mark Amery Nov 01 '13 at 17:22
40

Use iter to create a list iterator e.g.

return iter(List)

though if you already have a list, you can just return that, which will be more efficient.

Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
  • Good question. And I have no answer. I will return the whole list. I just thought returning a generator was a good idea because everything in the project used generators (except this place - i get this list from a library that is not lazy). – bodacydo Mar 23 '10 at 08:29
  • 5
    This is overkill as the call to `iter` is completely redundant. – msw Sep 04 '13 at 18:15
  • 4
    `iter` is an overkill but it is not completely redundant, it can be used to remember where are you while iterating through a list and you can pass it along, with list you will have to pass an index too – Anurag Uniyal Apr 11 '15 at 22:35
  • 11
    @Anurag - This doesn't seem to answer the question: what if I don't want to return at that point, I want to yield everything from the list and then continue (possibly yielding more stuff) ? This is pretty common (e.g. when walking a recursive structure) and, like bodacydo, I don't think the "for x in list yield x" solution is Pythonic. – Edmund Jan 15 '16 at 23:15
  • @Edmund answer is specific to question OP asked, and he has accepted it as answer. What you are suggesting are not his needs, may be you can ask a separate question. – Anurag Uniyal Jan 17 '16 at 20:56
1

You can build a generator by saying

(x for x in List)
Johannes Charra
  • 29,455
  • 6
  • 42
  • 51