2017-07-17 3 views
0

私はfinding all cycles in graph implementationについての別のディスカッションスレッドを読むと、この質問に出くわしました。誰もこの例でこのキーワードのペアの使用を説明できますか?ありがとう。Pythonでは "continue"と "yield"というキーワードのペアは何をしていますか?

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

2つのキーワードは密接に関連していません。

continueキーワードは、ループ(forまたはwhile声明)の体内で発生し、代わりにループ本体の残りの部分かかわらず、継続のループの先頭を返すために、制御の流れが発生することができます。これは、ループ本体の残りの部分全体をifまたはelseブロックにインデントする代わりに、しばしば使用されます。この:

はこれにまったく同じです:

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ステートメントに達するたびに、関数の実行は一時停止し、反復の値としてyieldされた値(または値が指定されていない場合はNone)が与えられます。 (誰かが気軽に何か「ジェネレータ」を呼び出すと、ジェネレータ関数かジェネレータオブジェクトのどちらかを意味するかもしれません)。

ここでは、ジェネレータを使って123yieldに多少似

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) 

もう一つのキーワードはまた、関数だけで理にかなっている、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を使用するとスタイルの選択肢が増え、コードのロジックやパフォーマンスにはほとんど影響しません(見た目だけ)。

関連する問題