Python Return 和 yield 在同一个函数中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26595895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:43:37  来源:igfitidea点击:

Return and yield in the same function

pythonyield

提问by nekomimi

What exactly happens, when yield and return are used in the same function in Python, like this?

当在 Python 中的同一个函数中使用 yield 和 return 时,到底会发生什么,像这样?

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?

它还是发电机吗?

采纳答案by NPE

Yes, it' still a generator. The returnis (almost) equivalent to raising StopIteration.

是的,它仍然是一个发电机。该return是(几乎),相当于提高StopIteration

PEP 255spells it out:

PEP 255阐明了这一点:

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.

规格:返回

生成器函数还可以包含以下形式的返回语句:

"return"

请注意,在生成器主体中的 return 语句中不允许使用 expression_list(当然,它们可能出现在嵌套在生成器中的非生成器函数的主体中)。

当遇到 return 语句时,控制像在任何函数 return 中一样进行,执行适当的 finally 子句(如果存在)。然后引发 StopIteration 异常,表示迭代器已耗尽。如果控制在没有显式返回的情况下从生成器的末尾流出,也会引发 StopIteration 异常。

请注意,对于生成器函数和非生成器函数,返回意味着“我完成了,没有什么有趣的东西要返回”。

请注意, return 并不总是等同于引发 StopIteration:区别在于如何处理封闭的 try/except 构造。例如,

>>> def f1():
...     try:
...         return
...     except:
...        yield 1
>>> print list(f1())
[]

因为,就像在任何函数中一样, return 只是退出,但是

>>> def f2():
...     try:
...         raise StopIteration
...     except:
...         yield 42
>>> print list(f2())
[42]

因为 StopIteration 被一个空的“except”捕获,任何异常也是如此。

回答by Ashwini Chaudhary

Yes, it is still a generator. An empty returnor return Nonecan be used to end a generator function. It is equivalent to raising a StopIteration(see @NPE's answerfor details).

是的,它仍然是一个发电机。空的returnorreturn None可用于结束生成器功能。它相当于提高一个StopIteration(有关详细信息,请参阅@NPE 的答案)。

Note that a return with non-None arguments is a SyntaxErrorin Python versions prior to 3.3.

请注意,SyntaxError在 3.3 之前的 Python 版本中,具有非 None 参数的返回是 a 。

As pointed out by @BrenBarn in comments starting from Python 3.3 the return value is now passed to StopIteration.

正如@BrenBarn 在从 Python 3.3 开始的注释中指出的,返回值现在被传递给 StopIteration.

From PEP 380:

来自PEP 380

In a generator, the statement

return value

is semantically equivalent to

raise StopIteration(value)

在生成器中,语句

return value

在语义上等同于

raise StopIteration(value)

回答by William Rusnack

There is a way to accomplish having a yield and return method in a function that allows you to return a value or generator.

有一种方法可以在允许您返回值或生成器的函数中实现 yield 和 return 方法。

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

回答by Rick

Note: you don't get StopIterationexception with the example below.

注意:StopIteration以下示例不会出现异常。

def odd(max):
    n = 0
    while n < max:
        yield n
        n = n + 1
    return 'done'


for x in odd(3):
    print(x)

The forloop catches it. That's its signal to stop

for循环抓住了它。这是它停止的信号

But you can catch it in this way:

但是你可以通过这种方式捕捉它:

g = odd(3)

while True:
    try:
        x = next(g)
        print(x)
    except StopIteration as e:
        print("g return value:", e.value)
        break