Why can't I use yield with return?

我们两清 提交于 2019-11-29 18:27:39

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.

Torxed

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.

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

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
    

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