There is this code:
def f():
return 3
return (i for i in range(10))
x = f()
print(type(x)) # int
def g():
return 3
for i in range(10):
yield i
y = g()
print(type(y)) # generator
Why f
returns int
when there is return generator statement? I guess that yield
and generator expression both returns generators (at least when the statement return 3
is removed) but are there some other rules of function compilation when there is once generator expression returned and second time when there is yield
keyword inside?
This was tested in Python 3.3
As soon as you use a yield
statement in a function body, it becomes a generator. Calling a generator function just returns that generator object. It is no longer a normal function; the generator object has taken over control instead.
From the yield
expression documentation:
Using a
yield
expression in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. The execution starts when one of the generator’s methods is called.
In a regular function, calling that function immediately switches control to that function body, and you are simply testing the result of the function, set by it's return
statement. In a generator function, return
still signals the end of the generator function, but that results in a StopIteration
exception being raised instead. But until you call one of the 4 generator methods (.__next__()
, .send()
, .throw()
or .close()
), the generator function body is not executed at all.
For your specific function f()
, you have a regular function, that contains a generator. The function itself is nothing special, other that that it exits early when return 3
is executed. The generator expression on the next line stands on its own, it does not influence the function in which it is defined. You can define it without the function:
>>> (i for i in range(10))
<generator object <genexpr> at 0x101472730>
Using a generator expression produces a generator object, just like using yield
in a function, then calling that function produces a generator object. So you could have called g()
in f()
with the same result as using the generator expression:
def f():
return 3
return g()
g()
is still a generator function, but using it in f()
does not make f()
a generator function too. Only yield
can do that.
def f():
return 3
return (i for i in range(10))
is the same as
def f():
return 3
The second return statement never gets executed, just by having a generator expression within f
does not make it a 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