在Python中,“continue”和“yield”这对关键字有什么作用?

2024-07-05 09:15:11 发布

您现在位置:Python中文网/ 问答频道 /正文

当我读到另一篇关于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]]

Tags: pathinnodeforifstartgraphnext
1条回答
网友
1楼 · 发布于 2024-07-05 09:15:11

这两个关键词没有紧密联系。在

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

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

完全等同于:

^{pr2}$

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

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函数依次使用yield和{}。它首先产生一个值(在请求下一个值之前停止生成器函数的执行),然后一旦恢复执行,它就回到循环的开始。在

如果您愿意,可以重写函数以避免这两种情况之一(尽管结果函数的工作方式会有所不同,因为它不再是惰性生成器):

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而不是更多的缩进更多的是一种样式选择,并且对代码的逻辑或性能没有太大的影响(只影响代码的外观)。在

相关问题 更多 >