web-dev-qa-db-ja.com

x for y():これはどのように機能しますか?

端末でカーソルを回転させるコードを探していたところ、これが見つかりました。コードで何が起こっているのかと思っていました。特にfor c in spinning_cursor():この構文は見たことがありません。 yieldを使用してジェネレータから一度に1つの要素を返し、これがcに割り当てられているためですか? y()での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')
76
Paul

yieldを使用すると、関数が generator になります。ジェネレータは iterator の特殊なタイプです。 forは常に反復可能オブジェクトをループし、各要素を順番に取得して、指定した名前に割り当てます。

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

forループはまさにそれを行い、ジェネレーターが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ループはスクリプトを強制終了しない限り永遠に続きます。

より退屈な(しかしより効率的な)代替手段は itertools.cycle() を使用することです:

from itertools import cycle

spinning_cursor = cycle('/-\|')
47
Martijn Pieters

Pythonでは、forステートメントを使用して要素を反復できます。

documentation によると:

Pythonのforステートメントは、シーケンス内の項目(リストまたは文字列)を、シーケンス内に出現する順序で反復します

ここで、要素はspinning_cursor()の戻り値になります。

5
aymericbeaumet

for c in spinning_cursor()構文は_for-each_ループです。 spinning_cursor()によって返されたイテレータの各項目を反復処理します。

ループの内側は:

  1. キャラクターを標準出力に書き込み、フラッシュして表示します。
  2. 1/10秒寝る
  3. _\b_を書き込みます。これは、バックスペースとして解釈されます(最後の文字を削除します)。これはループの最後で発生するため、最初の反復中には書き込まれず、ステップ1のフラッシュ呼び出しを共有していることに注意してください。

spinning_cursor()generator を返します。これは、反復を開始するまで実際には実行されません。 _'/-\|'_を順番に永久にループするようです。それは、反復する無限のリストを持つようなものです。

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

_/
-
\
|
_
3
thegrinner

spinning_cursor関数は、イテラブル(yieldからのジェネレーター)を返します。

for c in spinning_cursor():

と同じになります

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

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')
2