2016-06-28 6 views
8

私はRaymond Hettingerさんのお話Transforming Code into Beautiful, Idiomatic Pythonを見ていましたが、彼は私が決して知らなかったこの形のiterを持ってきます。彼の例は以下の通りである。iter(callable、sentinel)の用途は何ですか?

の代わりに:

blocks = [] 
while True: 
    block = f.read(32) 
    if block == '': 
     break 
    blocks.append(block) 

用途:

blocks = [] 
read_block = partial(f.read, 32) 
for block in iter(read_block, ''): 
    blocks.append(block) 

iterdocumentationを確認した後、私は同様の例が見つかりました:

with open('mydata.txt') as fp: 
    for line in iter(fp.readline, ''): 
     process_line(line) 

この私にはかなり役立つように見えますが、私はあなたのことをPythonis I/O-readループを伴わないこの構造の例を知っていますか?おそらく標準ライブラリですか?

私は次のような非常に不自然な例、と考えることができます:

>>> def f(): 
...  f.count += 1 
...  return f.count 
... 
>>> f.count = 0 
>>> list(iter(f,20)) 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
>>> 

しかし、明らかに、これは任意のより便利なビルトインイテラブルものではありません。また、関数に状態を代入しているときに、コードの臭いのように思えます。その時点で、私はおそらくクラスで作業する必要がありますが、クラスを書くつもりなら、私が達成したいもののイテレータプロトコルを実装することもできます。ここで

+2

は、私はより良いこの質問をする方法についてのいくつかのフィードバックをいただければ幸いです。 –

答えて

4

、私は2つのために見てきた主な用途は、ITER ARG変換伴う:空のエラーメッセージで(ちょうどいくつかのサードパーティの機能を代わりに例えば使用して例外のことのように設計されていることを、ここで想定してみましょう) C APIに似た関数(暗黙の状態、反復の概念なし)をイテレータに提供します。ファイルのようなオブジェクトは一般的な例ですが、他のライブラリではC APIをうまくラップしていません。予想されるパターンは、リソースが開かれているFindFirstFile/FindNextFileなどのAPIで見られるパターンで、各呼び出しは内部状態を進め、新しい値またはマーカー変数(CのNULLなど)を返します。通常、イテレータプロトコルを実装するクラスにラップするのが最適ですが、APIがCレベルのビルトインである間にラッピングを行うと、使用が遅くなり、2つの引数がCで実装されますバイトコードの追加実行を避けることができます。

>>> from functools import partial 
>>> ba = bytearray(b'aaaa\n'*5) 
>>> for i in iter(partial(ba.rfind, b'\n'), -1): 
...  print(i) 
...  ba[i:] = b'' 
... 
24 
19 
14 
9 
4 

別場合が場合である:

他の例としては、処理が完了しただけ後行を除去すること、のByteArrayのライン上に逆の順序でループ、例えば、ループ自体の間に変更された可変オブジェクトを含みますたとえば、イテラブルをnのグループにグループ化し、入力反復可能性がnの偶数倍でない場合、最終グループがnアイテム未満になるように効率的な(確かに醜い場合)効率的な方法を使用して私が実際に使用した長さの項目(これは私が通常itertools.takewhile(boolの代わりに2つのarg iter):

# from future_builtins import map # Python 2 only 
from itertools import starmap, islice, repeat 

def grouper(n, iterable): 
    '''Returns a generator yielding n sized tuples from iterable 

    For iterables not evenly divisible by n, the final group will be undersized. 
    ''' 
    # Keep islicing n items and converting to groups until we hit an empty slice 
    return iter(map(tuple, starmap(islice, repeat((iter(iterable), n)))).__next__,()) # Use .next instead of .__next__ on Py2 

別の用途:センチネル値(例えばNone)に続いて、単一のファイルに複数の漬けオブジェクトを書き込むので、unpickle化するとき、あなたが代わりに何とか数を覚えておくことが必要で、このイディオムを使用することができますアイテム漬け、またはEOFErrorまで何度もloadを呼び出すために必要とする:質問をdownvotedまたは閉じるために投票した人のために

with open('picklefile', 'rb') as f: 
    for obj in iter(pickle.Unpickler(f).load, None): 
     ... process an object ... 
+0

C APIに似た関数を変換することについての背景をありがとう、それはまさに私が探していたものです。 –

8

は私が思い付いた愚かな例です:

from functools import partial 
from random import randint 

pull_trigger = partial(randint, 1, 6) 

print('Starting a game of Russian Roulette...') 
print('--------------------------------------') 

for i in iter(pull_trigger, 6): 
    print('I am still alive, selected', i) 

print('Oops, game over, I am dead! :(') 

出力例:

$ python3 roulette.py 
Starting a game of Russian Roulette... 
-------------------------------------- 
I am still alive, selected 2 
I am still alive, selected 4 
I am still alive, selected 2 
I am still alive, selected 5 
Oops, game over, I am dead! :(

アイデアは、ランダムな値を生成するジェネレータを持つことである、とあなたが一度処理したいです特定の値が選択されています。たとえば、確率的プロセスの平均結果を決定しようとするシミュレーションの各実行でこのパターンを使用します。あなたは、モデリングだろうプロセスはおそらく、単純なサイコロのロールよりもボンネットの下にはるかに複雑になりもちろん

...

私はそれが成功するまで繰り返し演算を実行することになると考えることができます別の例として、示されました

原則として
from foo_lib import guess_password 

for msg in iter(guess_password, ''): 
    print('Incorrect attempt, details:', msg) 

# protection cracked, continue... 
+0

自分でランダムな値を返す関数を考えるべきでした! –

関連する問題