Catching the return value of a generator at the end of a for loop

given the following code def g(): yield 2 yield 3 return 6 for x in g(): print(x) The output is obviously 2 3 As far as I know, there is currently no way to capture the StopIteration value when the generator is used in a for loop. Is it true? If not, would a syntax like: for x in g() return v: print(x) print(v) # prints 6 be useful? It would be syntactic sugar for (corner cases omitted) def g(): yield 2 yield 3 return 6 it = iter(g()) while True: try: x = next(it) except StopIteration as exc: v = exc.value break else: print(x) print(v) -- Kind regards, Stefano Borini

Hello, 2019-04-16 Stefano Borini <stefano.borini@gmail.com> dixit:
I like the idea -- occasionally (when dealing with `yield from`-intensive code...) I wish such a shortcut existed. I don't like the proposed keyword. Maybe `as` would be better? for x in g() as v: print(x) print(v) Cheers, *j

I don't like it either. Ideally, I would want "returning", but of course a new keyword is not an option for such limited use case. "as" is probably much better, and the behavior of as in other contexts is very similar. On Tue, 16 Apr 2019 at 23:42, Jan Kaliszewski <zuo@kaliszewski.net> wrote:
-- Kind regards, Stefano Borini

On Tue, Apr 16, 2019 at 09:54:31PM +0100, Stefano Borini wrote:
I think you are correct. See https://bugs.python.org/issue35756
I don't know. You tell us -- why do you care about the StopIteration value in a for-loop? I think your question here is backwards. You should not start with syntax to capture the exception value, then ask if it would be useful. You should start by finding a reason why we would want to capture the exception value, and only then worry about whether we need syntax for it, or some other method. -- Steven

On Wed, 17 Apr 2019 at 00:45, Steven D'Aprano <steve@pearwood.info> wrote:
I don't know. You tell us -- why do you care about the StopIteration value in a for-loop?
I came across the idea while I was reading various PEPs, so I don't have an actual use case under my hands right now. However, in the past I had a circumstance that might have called for that. Of course it was easy to workaround. I was iterating over plugins as they were loaded, using a generator, and setting up some configuration options. e.g. def load_plugins(): for plugin in pluginloader: if plugin.success: plugin.setup(configuration_vars) In some cases, some of the plugins failed to load (e.g. because there was a syntax error in their content). In my design, the plugin class instance had a flag indicating if it was successful or not (plugin.success). I wanted to keep track of how many plugins failed to load and how many were successful, so I could return that information to the user. This calls for counting at the level of load_plugins(). If pluginloader returned a tuple (num_successful, num_failed) it would save a (agreed trivial) need to count this information in the caller. -- Kind regards, Stefano Borini

On 4/16/2019 4:54 PM, Stefano Borini wrote:
Syntactic sugar should be reserved for fairly common cases, not for extremely rare cases.
If a for loop user needs to see 6, it should be yielded. Adding non-None return values to StopIteration is fairly new, and was/is intended for cases where a generator is not being used as a simple forward iterator. For such special cases, special code like the following should be used.
-- Terry Jan Reedy

Hello, 2019-04-16 Stefano Borini <stefano.borini@gmail.com> dixit:
I like the idea -- occasionally (when dealing with `yield from`-intensive code...) I wish such a shortcut existed. I don't like the proposed keyword. Maybe `as` would be better? for x in g() as v: print(x) print(v) Cheers, *j

I don't like it either. Ideally, I would want "returning", but of course a new keyword is not an option for such limited use case. "as" is probably much better, and the behavior of as in other contexts is very similar. On Tue, 16 Apr 2019 at 23:42, Jan Kaliszewski <zuo@kaliszewski.net> wrote:
-- Kind regards, Stefano Borini

On Tue, Apr 16, 2019 at 09:54:31PM +0100, Stefano Borini wrote:
I think you are correct. See https://bugs.python.org/issue35756
I don't know. You tell us -- why do you care about the StopIteration value in a for-loop? I think your question here is backwards. You should not start with syntax to capture the exception value, then ask if it would be useful. You should start by finding a reason why we would want to capture the exception value, and only then worry about whether we need syntax for it, or some other method. -- Steven

On Wed, 17 Apr 2019 at 00:45, Steven D'Aprano <steve@pearwood.info> wrote:
I don't know. You tell us -- why do you care about the StopIteration value in a for-loop?
I came across the idea while I was reading various PEPs, so I don't have an actual use case under my hands right now. However, in the past I had a circumstance that might have called for that. Of course it was easy to workaround. I was iterating over plugins as they were loaded, using a generator, and setting up some configuration options. e.g. def load_plugins(): for plugin in pluginloader: if plugin.success: plugin.setup(configuration_vars) In some cases, some of the plugins failed to load (e.g. because there was a syntax error in their content). In my design, the plugin class instance had a flag indicating if it was successful or not (plugin.success). I wanted to keep track of how many plugins failed to load and how many were successful, so I could return that information to the user. This calls for counting at the level of load_plugins(). If pluginloader returned a tuple (num_successful, num_failed) it would save a (agreed trivial) need to count this information in the caller. -- Kind regards, Stefano Borini

On 4/16/2019 4:54 PM, Stefano Borini wrote:
Syntactic sugar should be reserved for fairly common cases, not for extremely rare cases.
If a for loop user needs to see 6, it should be yielded. Adding non-None return values to StopIteration is fairly new, and was/is intended for cases where a generator is not being used as a simple forward iterator. For such special cases, special code like the following should be used.
-- Terry Jan Reedy
participants (5)
-
Greg Ewing
-
Jan Kaliszewski
-
Stefano Borini
-
Steven D'Aprano
-
Terry Reedy