24

I have a Python generator that can call itself to get more elements to yield. It looks like this:

def gen(list):
    # ...
    if list:
        for x in gen(list[1:]):
            yield x

My question is about the last two lines: is there a more concise way to express this? I am hoping for something like this (understanding this isn't valid Python as-is):

def gen(list):
    # ...
    if list:
        yield each in gen(list[1:])
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • I don't quite get what this is supposed to do, I originally thought it was just a naive way of converting a list to a generator but I was mistaken. Could you enlighten me? – Davy8 Jun 06 '11 at 20:45
  • Correct me if I'm wrong, but that code looks like it would always return an empty list. I assume there must be other yields in the comment? – Dunes Jun 06 '11 at 21:25
  • @Dunes: yes, there are other yields in the comment. – John Zwinck Jun 07 '11 at 01:27
  • @Davy8: it's not a wrapper or converter, it's a custom generator I wrote. It takes a list of things and generates another list, which may contain some of the same things, or not. A "filter" of sorts. – John Zwinck Jun 07 '11 at 01:28

4 Answers4

26

There's been some call for a yield from or the like that "passes through" all the values returned by a subgenerator. See PEP 380 for some ideas that have been bounced around. However, nothing has been implemented yet. Your first example is correct.

kindall
  • 178,883
  • 35
  • 278
  • 309
17

Python 3.3 added the yield from keyword. Here's a comparison between what you currently have and code using the new keyword:

yield_from_test.py:

def gen_for(a_list):
    if a_list:
        yield a_list[0]
        for x in gen_for(a_list[1:]):
            yield x

def gen_yield(a_list):
    if a_list:
        yield a_list[0]
        yield from gen_yield(a_list[1:])

if __name__ == '__main__':
    assert list(gen_for([1,2,3])) == list(gen_yield([1,2,3]))
    print(list(gen_yield([1,2,3])))

» python3 yield_from_test.py [1, 2, 3]

Carl G
  • 17,394
  • 14
  • 91
  • 115
5

Your code sample is very idiomatic and concise, no need and no real chance for further improvements and especially not when it comes at readability.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
  • 1
    Node generators have [a syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*) for delegating generation to another generator: `yield* my_generator(...)`. I personally find that more concise. And things become idiomatic with a PEP and adoption... – Carl G Mar 19 '18 at 18:41
4

Your first example is the proper solution.

mikerobi
  • 20,527
  • 5
  • 46
  • 42