Why can't I use yield with return?

北城余情 提交于 2019-11-28 14:15:41

问题


I would like you to consider the following code:

def func(alist):
    if len(alist) == 1:
        return arg * 2
    for item in alist:
        yield item * 2

When I run it, I get this error:

SyntaxError: 'return' with argument inside generator

Now, I realize that I cannot do this. However, I would like to know why. What exactly is going on behind the scenes that is causing Python to throw the SyntaxError?


回答1:


Python has to decide whether a function is a generator at bytecode compilation time. This is because the semantics of generators say that none of the code in a generator function runs before the first next call; the generator function returns a generator iterator that, when next is called, runs the generator code. Thus, Python can't decide whether a function should be a generator or not by running it until it hits a yield or a return; instead, the presence of a yield in a function signals that the function is a generator.




回答2:


See here: What does the "yield" keyword do in Python?

This describes your issue in detail. In short, because the way Python will interprate the function (either as an generating object or a returning object, everything in Python is objects and some things will define that object as a specific type. In this case Yield is a generating object)

TL;DR: You can't use yield and return within the same function. Use either one as many times as you wan't within the function, just not both.




回答3:


Is not that, you cannot use a return with yield, but rather, you cannot use return with argument, when your function has a yield making it a generator

You might want to change your implementation to

def func(lis):
    for item in lis:
        yield item * 2



回答4:


What you want is indeed possible:

def func(lis):
    if len(lis) == 1:
        return lis[0] * 2
    else:
        return (item * 2 for item in lis)

This returns a value in the one case and a generator in the other case.

But be aware that this will lead to problems: On every call, you will have to make the distinction

res = func(lis)
if len(lis) == 1:
    print res # my value
else:
    for i in res: print i # several values

It is much more advisable to make the two use cases distinct:

  1. You can do

    def func(val):
        return val * 2
    

    and, when you need, do either of

    reslist = [func(i) for i in lis]
    resgen = (func(i) for i in lis)
    

    or

  2. you can do

    def func(lis):
        for item in lis:
            yield lis[0] * 2
    
    def func1(val):
        for i in func([val]):
            return i # returns the first value
    



回答5:


The other answers already explained the yield/return issue. You can just use map to make this much simpler:

def func(lis):
    return map(lambda item: item * 2, lis)
   # similar to: return [item * 2 for item in lis]

Of course, this will always return a list, because lis is a list, even if it only has one item. You can change it to a compound statement:

def func(lis):
    return map(lambda item: item * 2, lis) if len(lis) > 1 else lis[0] * 2


来源:https://stackoverflow.com/questions/18215828/why-cant-i-use-yield-with-return

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!