目次|前のセクション(6.1反復プロトコル)|次のセクション(6.3生産者/消費者)
6.2カスタムイテレーション
リベートウェブサイトwww.cpa5.cnこのセクションでは、ジェネレーター関数を使用して反復をカスタマイズする方法について説明します。
問題
反復モードをカスタマイズするとします。
例:カウントダウン:
>>> for x in countdown(10):
... print(x, end=' ')
...
10 9 8 7 6 5 4 3 2 1
>>>
これを行う簡単な方法があります。
ビルダー
ジェネレーターは、反復を定義する関数です。
def countdown(n):
while n > 0:
yield n
n -= 1
例:
>>> for x in countdown(10):
... print(x, end=' ')
...
10 9 8 7 6 5 4 3 2 1
>>>
yield
ジェネレーターと呼ばれる関数ステートメントの使用。
ジェネレータ関数の動作は通常の関数とは異なります。ジェネレーター関数を呼び出すと、関数をすぐに実行する代わりに、ジェネレーターオブジェクトが作成されます。
def countdown(n):
# Added a print statement
print('Counting down from', n)
while n > 0:
yield n
n -= 1
>>> x = countdown(10)
# There is NO PRINT STATEMENT
>>> x
# x is a generator object
<generator object at 0x58490>
>>>
ジェネレーター関数は__next__()
、メソッドが呼び出されたときにのみ実行されます。
>>> x = countdown(10)
>>> x
<generator object at 0x58490>
>>> x.__next__()
Counting down from 10
10
>>>
yield
値は生成されますが、サスペンド機能が実行されます。__next__()
メソッド(resume)のときに再開する次の呼び出しのビルダー関数、
>>> x.__next__()
9
>>> x.__next__()
8
ジェネレータが最後の値を返したときに、もう一度繰り返すとエラーが発生します。
>>> x.__next__()
1
>>> x.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in ? StopIteration
>>>
観察:ジェネレーター関数によって実装されるプロトコルは、リスト、タプル、辞書、およびファイルのforステートメントによって使用される基礎となるプロトコルと同じです。
運動
演習6.4:単純なジェネレーター
カスタム反復が必要な場合は、常にジェネレーター関数を検討する必要があります。ジェネレーター関数は簡単に記述できます-反復ロジックを実行するために必要な関数を作成し、yield
送信値を使用します。
たとえば、ファイルの各行で一致する部分文字列を検索するジェネレータを作成するには、次のようにします。
>>> def filematch(filename, substr):
with open(filename, 'r') as f:
for line in f:
if substr in line:
yield line
>>> for line in open('Data/portfolio.csv'):
print(line, end='')
name,shares,price
"AA",100,32.20
"IBM",50,91.10
"CAT",150,83.44
"MSFT",200,51.23
"GE",95,40.37
"MSFT",50,65.10
"IBM",100,70.44
>>> for line in filematch('Data/portfolio.csv', 'IBM'):
print(line, end='')
"IBM",50,91.10
"IBM",100,70.44
>>>
これは興味深いアイデアです。関数内のカスタム処理を非表示にして、関数をforループに適用できます。次の例では、より異常な状況を調査します。
演習6.5:ストリーミングデータソースを監視する
ジェネレーターは、リアルタイムのデータソース(ログファイル、株式市場のニュースなど)を監視するために使用できます。このパートでは、「ジェネレーターを使用してリアルタイムのデータソースを監視する」というアイデアを探ります。まず、以下の指示に厳密に従ってください。
Data/stocksim.py
株式市場のデータを模倣するために、リアルタイムのデータが引き続きData/stocklog.csv
ファイルに書き込まれます。別のコマンドラインウィンドウを開き、Data/
ディレクトリを入力して、stocksim.py
プログラムを実行します。
bash % python3 stocksim.py
Windowsシステムを使用している場合は、stocksim.py
ファイルを見つけて、ファイルをダブルクリックして実行します。次に、それをプログラム用に取っておき(その時点で実行されています)、別のコマンドラインウィンドウを開き、シミュレーションプログラムがstocksim.py
データData/stocklog.csv
ファイルを書き込んでいることを確認します(翻訳:)データファイルを書き込んでいます(翻訳:Linuxシステムを使用している場合は、データディレクトリに移動し、tail -f stocklog.csv
コマンドを使用して表示します)。数秒ごとに新しいテキスト行がData/stocklog.csv
ファイルに追加されます。同様に、プログラムをバックグラウンドで実行します-プログラムは数時間実行されます(これについては心配しないでください)。
stocksim.py
プログラムを実行した後Data/stocklog.csv
、ファイルを開き、ファイルの最後に移動して、新しい出力を表示するプログラムを作成しましょう。at Workディレクトリfollow.py
ファイルを作成し、次のコードを入力してください。
# follow.py
import os
import time
f = open('Data/stocklog.csv')
f.seek(0, os.SEEK_END) # Move file pointer 0 bytes from end of file
while True:
line = f.readline()
if line == '':
time.sleep(0.1) # Sleep briefly and retry
continue
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if change < 0:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
follow.py
プログラムを実行すると、リアルタイムの株価情報(株式相場表示)が表示されます。follow.py
ログファイルtail -f
コマンドを表示するUnixライクなシステムのコード。
注:この例でreadline()
は、使用方法は、一般に、わずかに異なる実施形態(通常はfor
循環)のファイルから読み取られます。この場合、readline()
endを使用して重複ファイルを検出し、新しいデータが追加されているかどうかを確認します(readline()
メソッドは新しいデータまたは空の文字列を返します)。
演習6.6:ジェネレーターを使用してデータを生成する
演習6.5のコードを見ると、コードの最初の部分で数行のデータが生成さwhile
れ、ステートメントの消費データの最後で循環していることがわかります。ジェネレーターの主な機能の1つは、データを生成するコードを再利用可能な関数に移動できることです。
6.5実践コードを編集して、ジェネレーター関数を介しfollow(filename)
て実行ファイルを読み取るようにします。次のコードが機能するように、変更を実装してください。
>>> for line in follow('Data/stocklog.csv'):
print(line, end='')
... Should see lines of output produced here ...
コードが次のようになるように、株価コードを変更してください。
if __name__ == '__main__':
for line in follow('Data/stocklog.csv'):
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if change < 0:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
演習6.7:株式ポートフォリオを表示する
follow.py
プログラムを変更して、プログラムがストリーミング株式データを表示し、それらの株式の情報株式ポートフォリオを印刷できるようにします。例:
if __name__ == '__main__':
import report
portfolio = report.read_portfolio('Data/portfolio.csv')
for line in follow('Data/stocklog.csv'):
fields = line.split(',')
name = fields[0].strip('"')
price = float(fields[1])
change = float(fields[4])
if name in portfolio:
print(f'{name:>10s} {price:>10.2f} {change:>10.2f}')
注:このコードを実行できるようにするにPortfolio
は、クラスがin
演算子をサポートしている必要があります。Portfolio
クラスが__contains__()
演算子を実装していることを確認するには、演習6.3を参照してください。
話し合います
ここでは、興味深い反復パターン(ファイルの最後にある行の読み取り)を関数に移動します。follow()
関数は、あらゆるプログラムで使用できる完全にユニバーサルなユーティリティになりました。たとえば、このfollow()
関数を使用して、他のデータソースと同様に、サーバーログ、デバッグログを表示できます。
目次|前のセクション(6.1反復プロトコル)|次のセクション(6.3生産者/消費者)
注:完全な翻訳については、https://github.com/codists/practical-python-zhを参照してください