关键字“继续”和“产量”在 Python 中的作用是啥?

Posted

技术标签:

【中文标题】关键字“继续”和“产量”在 Python 中的作用是啥?【英文标题】:What does the pair of keywords, "continue" and "yield" do in Python?关键字“继续”和“产量”在 Python 中的作用是什么? 【发布时间】:2017-07-17 08:01:22 【问题描述】:

当我阅读另​​一个关于finding all cycles in graph implementation 的讨论线程时,我遇到了这个问题。谁能解释一下这个例子中这对关键字的用法?谢谢。

01 def dfs(graph, start, end):
02     fringe = [(start, [])]
03     while fringe:
04         state, path = fringe.pop()
05         if path and state == end:
06             yield path
07             continue
08         for next_state in graph[state]:
09             if next_state in path:
10                 continue
11             fringe.append((next_state, path+[next_state]))

>>> graph =  1: [2, 3, 5], 2: [1], 3: [1], 4: [2], 5: [2] 
>>> cycles = [[node]+path  for node in graph for path in dfs(graph, node, node)]
>>> len(cycles)
7
>>> cycles
[[1, 5, 2, 1], [1, 3, 1], [1, 2, 1], [2, 1, 5, 2], [2, 1, 2], [3, 1, 3], [5, 2, 1, 5]]

【问题讨论】:

【参考方案1】:

这两个关键字并不密切相关。

continue 关键字只能出现在循环体中(forwhile 语句),并导致控制流返回循环的顶部,而不是继续循环的其余部分循环体。它通常是在 ifelse 块中缩进循环体的整个其余部分的替代方法。这个:

while foo():
    if something():
        continue
    bar()
    baz()

完全等价于这个:

while foo():
    if not something():
        bar()
        baz()  # but note that these lines are more indented in this version!

另一个与continue密切相关的关键字是break,它导致控制流立即退出循环,而不是回到顶部。 continuebreak 都只能影响最近的循环,因此如果您有嵌套的控制结构,可能很难一次将它们全部打破(或 continue 内部循环内部的外部循环)。

yield 关键字完全不同。尽管它经常出现在循环中,但并非必须如此。相反,它只允许在函数体内。它将函数更改为“生成器函数”。当调用生成器函数时,它的代码不会立即运行,而是会创建一个“生成器对象”并将其返回给调用者。生成器对象是一种迭代器,可以通过for 循环(或手动调用next())对其进行迭代。只有当生成器对象被迭代时,函数的代码才会运行。每次到达yield 语句时,函数的执行都会暂停,产生的值(或None,如果未指定值)将作为迭代的值给出。 (请注意,当有人随便称某事物为“生成器”时,他们可能指的是生成器函数或生成器对象。通常从上下文中可以清楚地知道它们的含义。)

这是一些使用生成器打印123 的示例代码:

def generator_function():
    yield 1 # because it contains `yield` statements, this is a generator function
    yield 2
    yield 3

generator_object = generator_function() # you can create a variable for the generator object
for value in generator_object: # but often you'd create it on the same line as the loop
    print(value)

另一个与yield 有点相似的关键字是return,它也只在函数中有意义。它立即结束函数的执行以返回指定的值(如果没有指定值,则返回None)。

您展示的dfs 函数一个接一个地使用yieldcontinue。它的作用是首先产生一个值(停止生成器函数的执行,直到请求下一个值),然后一旦恢复执行,它就会回到循环的开头。

如果你愿意,你可以重写函数来避免其中任何一种(尽管生成的函数会有点不同,因为它不再是一个惰性生成器):

def dfs(graph, start, end):
   results = [] # maintain a list of results to avoid yielding
   fringe = [(start, [])]
   while fringe:
       state, path = fringe.pop()
       if path and state == end:
           results.add(path) # don't yield any more, just add the path to the results list
       else: # add an else block instead of using continue
           for next_state in graph[state]:
               if next_state not in path: # reverse the condition instead of continue
                   fringe.append((next_state, path+[next_state]))
    return results # return the results at the end of the function

我注意到该函数的生成器版本在大多数情况下可能会更好。使用 continue 而不是更多的缩进更多的是一种样式选择,并且对代码的逻辑或性能没有太大影响(仅影响它的外观)。

【讨论】:

你将如何在这个 dfs 函数中实现循环部分? 还有我该如何调用这个函数? @OscarDolloway:我想我不明白你的问题。循环计算是问题中的单独一行,重复调用dfs 函数。如果你愿意,你可以用我的版本做同样的事情。我想你可以把它放在一个函数中(甚至是一个内联 dfs 行为的函数),但这不是我在回答中想要做的。

以上是关于关键字“继续”和“产量”在 Python 中的作用是啥?的主要内容,如果未能解决你的问题,请参考以下文章

python的关键字yield有啥作用

python中的关键字global和nonlocal

我如何在conftest.py中设置会话详细信息以提高产量以及pytest中的fixture?

Python 函数和变量作用域

#抬抬小手学Python# Python 之作用域下的 global 和 nonlocal 关键字

睡眠方法和多线程的产量方法有什么区别?