2013-05-10 19 views
55

私は端末のカーソルを回転させるコードを探していて、これを見つけました。私はコード内で何が起きているのだろうと思っていた。特にfor c in spinning_cursor():私はこの構文を見たことがありません。それはyieldで一度に1つの要素をジェネレータから返すためですか?これはcに割り当てられていますか? x in y()のこれ以外の例はどれですか?for x():これはどのように機能しますか?

import sys 
import time 

def spinning_cursor(): 
    cursor='/-\|' 
    i = 0 
    while 1: 
     yield cursor[i] 
     i = (i + 1) % len(cursor) 

for c in spinning_cursor(): 
    sys.stdout.write(c) 
    sys.stdout.flush() 
    time.sleep(0.1) 
    sys.stdout.write('\b') 
+2

もう1つの例ですか?範囲(10)のiの場合:print(i) – antoyo

+0

ここですべてを見つけることができます:http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained – pylover

+0

収穫がどのように働いていたかの別の例ここの関数...私は今理解している例は必要ありません。また、ありがとう@pylover – Paul

答えて

38

yieldを使用すると、機能がgeneratorに変わります。発電機は特殊タイプのiteratorです。 forは、常に各要素を順番に取り出して、リストした名前に割り当てることで繰り返し実行できます。

spinning_cursor()はジェネレータを返します。spinning_cursor()のコードは、ジェネレータを反復処理するまで実際には実行されません。ジェネレータを反復すると、関数内のコードがyieldステートメントを通過するまで実行されます。このとき、式の結果が次の値として返され、実行は再び一時停止されます。

ループはまったく同じです。ジェネレータは、StopIteration(関数が返ってきたときに発生します)を起こしてシグナルを送るまで、next()のジェネレータを呼び出します。 next()の各戻り値は、順番にcに割り当てられます。

あなたは、プロンプトPythonで上のジェネレータを作成することで、これを見ることができます:

>>> def spinning_cursor(): 
...  cursor='/-\|' 
...  i = 0 
...  while 1: 
...   yield cursor[i] 
...   i = (i + 1) % len(cursor) 
... 
>>> sc = spinning_cursor() 
>>> sc 
<generator object spinning_cursor at 0x107a55eb0> 
>>> next(sc) 
'/' 
>>> next(sc) 
'-' 
>>> next(sc) 
'\\' 
>>> next(sc) 
'|' 

この特定のジェネレータを返すことはありませんので、StopIterationが発生されることはありませんし、スクリプトを殺していない限りforループは永遠に行きます。

+5

Waaaayは速すぎます。 – pcalcao

+0

ありがとうMartijn。このアイデアは、関数を呼び出すことであり、処理中にこの回転するカーソルを表示します。処理が終了すると停止します。だから、私はそれに取り組むでしょう。偉大な答えをありがとう。 – Paul

2

spinning_cursor関数は反復可能(yield from generator)を返します。

for c in spinning_cursor(): 

は、Pythonで

for i in [1, 2, 3, 4]: 
4

と同じになり、のための文は、要素を反復することができます。

よるdocumentation

Pythonのために、任意のシーケンス(リストまたは文字列)の項目の上に声明を反復処理し、ために彼らは

ここで、順番に表示されていること要素は戻り値spinning_cursor()になります。

3

for c in spinning_cursor()の構文は、ループfor-eachです。それはspinning_cursor()によって返されたイテレータ内の各アイテムを反復することになります。

ループの内側がします。それは表示させ

  1. は標準と同一面に文字を書きます。
  2. 10分の1秒間のスリープ
  3. 書き込み\bは、バックスペースとして解釈されます(最後の文字が削除されます)。これは、それが最初の反復時に書き込まれませんので、ループの最後で発生し、そうでない段階でのフラッシュコール

    spinning_cursor() が起こっている1

generatorを返すようにし、共有していることに注意してください実際には反復を開始するまで実行されます。 '/-\|'を順番にループしているようです。それは、反復する無限のリストを持つようなものです。

したがって、最終的な出力はASCIIスピナーになります。スクリプトを殺すまで、これらの文字が(同じ場所に)繰り返し表示されます。

/ 
- 
\ 
| 
2

Martijn Pieters説明は優れています。以下は、あなたが質問で持っていたのと同じコードの別の実装です。 itertools.cycleを使用してspinning_cursorと同じ結果が得られます。 itertoolsには、イテレータの優れた例と、独自のイテレータを作成するための関数が用意されています。イテレーターの理解を助けるかもしれません。

import sys, time, itertools 

for c in itertools.cycle('/-\|'): 
    sys.stdout.write(c) 
    sys.stdout.flush() 
    time.sleep(0.1) 
    sys.stdout.write('\b') 
+0

すばらしいことありがとう。 – Paul

関連する問題