2016-06-28 65 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 tas知道這個構造不包含I/O讀循環的任何例子嗎?也許在標準庫?

我能想到的很做作的例子,像下面這樣:

>>> 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] 
>>> 

但顯然這是沒有任何更多有用的內置iterables。另外,當你將狀態分配給一個函數時,它看起來像代碼給我的味道。那時候,我可能應該和一個類一起工作,但是如果我要編寫一個類,那麼我也可以爲我想完成的任何事情實現迭代器協議。

+2

對於downvoted問題或投票決定關閉的人,我希望得到一些反饋,如何更好地問這個問題。 –

回答

4

作爲一個規則,我已經看到了兩個主要用途ARG ITER涉及轉換函數類似於C API(隱式狀態,沒有迭代的概念)到迭代器。類似文件的對象是一個常見的例子,但是它出現在其他庫中的C API很差。您期望的模式可能是在類似FindFirstFile/FindNextFile的API中看到的模式,其中資源已打開,並且每個呼叫都前進內部狀態並返回新值或標記變量(如C中的NULL)。將它封裝在一個實現迭代器協議的類中通常是最好的,但是如果你必須自己做,而API是內置的C語言級別,那麼包裝可能會導致使用速度放緩,其中兩個參數在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 

另一種情況是當例如,如果輸入迭代不是偶數倍的n(例如,有效的(如果可以肯定地是醜陋的)方式來將迭代組分組到n項目的組中,同時允許最終的組小於n項目項目的長度(這一個我已經使用,雖然我通常使用itertools.takewhile(bool而不是兩個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例如),所以取儲存的時候,你可以用它代替需要以某種方式記數這個成語醃製的,或者需要一遍又一遍地撥打load直到EOFError項目:

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

我應該想到一個自己返回隨機值的函數! –