Mehdi
Mehdi

Reputation: 1525

Hybrid Generator/Function in Python

Is is possible in Python to have a generator that yields values in a loop be alternatively called as a normal function where the final value of that loop is returned? I tried setting a flag as argument and then choose to yield or return depending on that flag. But the mere existence of the keyword yield in a function transforms it automatically into a generator and Python complains that there was a return statement in a generator.

Here an example of such a function:

def function(generator=True):
    a = 0
    for i in range(10):
        a = i
        if generator:
            yield a
    if not generator:
        return a

Such a function would be useful for me when in some cases I just need the final result (eg. using it as residual function for optimization) while in other cases I need the incremental results after each iteration (for example using a differential model for a robot, updating the robot's pose with each new velocity command). For now I am having two functions where one has the yield and the other has the return. So is it possible to combine those two?

Upvotes: 0

Views: 318

Answers (2)

dfranca
dfranca

Reputation: 5322

it's still a generator, even calling return. I'd to not mix both generator/regular function anyway.

You can wrap something on top of the iterator, in case you need to loop through the results anyway.

A simple code that could do what you want:

last = None
for last in function(): pass

Now last holds the value you want and you can use it on your code.

The return inside a generator was added to Python 3.3 And it's equivalent to StopIteration(value)

return expr in a generator causes StopIteration(expr) to be raised upon exit from the generator.

In a generator, the statement

return value is semantically equivalent to

raise StopIteration(value) except that, as currently, the exception cannot be caught by except clauses within the returning generator.

Upvotes: 1

TigerhawkT3
TigerhawkT3

Reputation: 49330

You'll still have to iterate over it to get its single value, but you can use yield again instead of return to accomplish this.

>>> def function(generator=True):
...     a = 0
...     for i in range(10):
...         a = i
...         if generator:
...             yield a
...     if not generator:
...         yield a
...
>>> a = function()
>>> print(*a)
0 1 2 3 4 5 6 7 8 9
>>> a = function(0)
>>> print(a)
<generator object function at 0x0000000001603240>
>>> print(*a)
9
>>> a = function(0)

Note that having return inside a generator is a SyntaxError in Python 2, but not Python 3. Replacing the return with yield produces the same result in 2 and 3.

Upvotes: 1

Related Questions