What exactly happens, when yield and return are used in the same function in Python, like this?
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
Is it still a generator?
Yes, it is still a generator. An empty return or return None can be used to end a generator function.
Yield is generally used to convert a regular Python function into a generator. Return is generally used for the end of the execution and “returns” the result to the caller statement. It replace the return of a function to suspend its execution without destroying local variables.
yield is a keyword that is used like return , except the function will return a generator.
Return sends a specified value back to its caller whereas Yield can produce a sequence of values. We should use yield when we want to iterate over a sequence, but don't want to store the entire sequence in memory. Yield is used in Python generators.
Yes, it' still a generator. The return
is (almost) equivalent to raising StopIteration
.
PEP 255 spells it out:
Specification: Return
A generator function can also contain return statements of the form:
"return"
Note that an expression_list is not allowed on return statements in the body of a generator (although, of course, they may appear in the bodies of non-generator functions nested within the generator).
When a return statement is encountered, control proceeds as in any function return, executing the appropriate finally clauses (if any exist). Then a StopIteration exception is raised, signalling that the iterator is exhausted. A StopIteration exception is also raised if control flows off the end of the generator without an explict return.
Note that return means "I'm done, and have nothing interesting to return", for both generator functions and non-generator functions.
Note that return isn't always equivalent to raising StopIteration: the difference lies in how enclosing try/except constructs are treated. For example,
>>> def f1(): ... try: ... return ... except: ... yield 1 >>> print list(f1()) []
because, as in any function, return simply exits, but
>>> def f2(): ... try: ... raise StopIteration ... except: ... yield 42 >>> print list(f2()) [42]
because StopIteration is captured by a bare "except", as is any exception.
Yes, it is still a generator. An empty return
or return None
can be used to end a generator function. It is equivalent to raising a StopIteration
(see @NPE's answer for details).
Note that a return with non-None arguments is a SyntaxError
in Python versions prior to 3.3.
As pointed out by @BrenBarn in comments starting from Python 3.3 the return value is now passed to StopIteration.
From PEP 380:
In a generator, the statement
return value
is semantically equivalent to
raise StopIteration(value)
There is a way to accomplish having a yield and return method in a function that allows you to return a value or generator.
It probably is not as clean as you would want but it does do what you expect.
Here's an example:
def six(how_many=None):
if how_many is None or how_many < 1:
return None # returns value
if how_many == 1:
return 6 # returns value
def iter_func():
for count in range(how_many):
yield 6
return iter_func() # returns generator
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With