LB--
LB--

Reputation: 2948

Why doesn't the Python interpreter implicitly create the generator?

#def func(param):
#    if param < 0:
#        return "test"
#    i = 0
#    while i < param:
#        yield i
#        i += 1
def func(param):
    if param < 0:
        return "test"
    def gen(n):
        i = 0
        while i < param:
            yield i
            i += 1
    return gen(param)

print(func(-1))
print(func(3))
g = func(3)
for i in range(0, 3):
    print(next(g))

Is there a reason that the Python interpreter can not convert the commented code to the actual code implicitly? This seems like this should be allowed, but I am wondering what repercussions there are that made them choose to disallow this.

Upvotes: 2

Views: 242

Answers (4)

dbr
dbr

Reputation: 169623

The reason is simply, if the def contains a yield statement, it creates a generator:

http://www.python.org/dev/peps/pep-0255/

The yield statement may only be used inside functions. A function that contains a yield statement is called a generator function. A generator function is an ordinary function object in all respects, but has the new CO_GENERATOR flag set in the code object's co_flags member.

That is how the interpreter distinguishes between a regular function, and a generator function. It's simple to implement, easy to reason about ("if it contains a yield, it's a generator")

The "conditional generator" behaviour you describe would be much more complex to implement, and in some cases not desirable (maybe the conditional should happen inside the first iteration of the generator, or maybe it should run as soon as you call func(...))

Your other code either returns a generator, or a string. If that's the interface you want, it seems like a perfectly good solution (but it's hard to make practical suggestions without a real example)

Upvotes: 0

zhangyangyu
zhangyangyu

Reputation: 8610

In python2.x, you can not return something in a generator:

>>> def func():
...     return 3
...     yield 3
... 
  File "<stdin>", line 3
SyntaxError: 'return' with argument inside generator
>>> 

In python3.x, use return in a generator means raise a StopIteration(<something>):

>>> def func():
...     return 3
...     yield 3
... 
>>> func().__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: 3
>>> 

I can not think about any reason for the interpreter to decide which part is a generator. It is hard and I think it is the responsibilities of programmers. And I even doubt whether return a value in a generator is a good implementation.

Upvotes: 2

Aviv Bar-el
Aviv Bar-el

Reputation: 81

generators are declared like functions but are different, you cant use a return statement in generator what you should do is:

def func(param):
    if param < 0:
        yield "test"
        raise StopIteration()
    i = 0
    while i < param:
        yield i
        i += 1

an even better implmention would be:

def func(param):
    if param < 0:
        raise ValueError("param must be a positive number")
    i = 0
    while i < param:
        yield i
        i += 1

Upvotes: 0

agf
agf

Reputation: 176880

When you call a generator function, you know what type of object it will return -- a generator. If we allowed generator functions to return, then you'd have to check the type of the return value before you could start iterating over the generator, so you'd no longer have a generator function -- just a function that might return a generator.

Upvotes: 2

Related Questions