所以,我正在观看Raymond Hettinger的演讲,将代码转换为美丽的,惯用的Python,并且他提出了iter我从未意识到的这种形式.他的例子如下:
代替:
blocks = []
while True:
block = f.read(32)
if block == '':
break
blocks.append(block)
Run Code Online (Sandbox Code Playgroud)
使用:
blocks = []
read_block = partial(f.read, 32)
for block in iter(read_block, ''):
blocks.append(block)
Run Code Online (Sandbox Code Playgroud)
检查完文档后iter,我发现了一个类似的例子:
with open('mydata.txt') as fp:
for line in iter(fp.readline, ''):
process_line(line)
Run Code Online (Sandbox Code Playgroud)
这看起来对我很有用,但我想知道你是否Pythonistas知道这个构造的任何不涉及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]
>>>
Run Code Online (Sandbox Code Playgroud)
但显然这对于内置的iterables来说并不是更有用.此外,当您将状态分配给函数时,似乎代码闻到了我.那时,我可能应该使用一个类,但如果我要编写一个类,我不妨实现迭代器协议,无论我想要完成什么.
pla*_*mut 10
这是我提出的一个愚蠢的例子:
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! :(')
Run Code Online (Sandbox Code Playgroud)
样本输出:
$ 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! :(
Run Code Online (Sandbox Code Playgroud)
我们的想法是拥有一个产生随机值的生成器,并且您希望在选择特定值后进行处理.例如,您可以在模拟的每次运行中使用此模式,以尝试确定随机过程的平均结果.
当然,你要建模的过程可能会比简单的骰子滚动更加复杂......
我能想到的另一个例子是重复执行一个操作,直到它成功为止,由一个空的错误消息表示(我们假设某些第三方函数的设计与此类似,而不是例如使用异常):
from foo_lib import guess_password
for msg in iter(guess_password, ''):
print('Incorrect attempt, details:', msg)
# protection cracked, continue...
Run Code Online (Sandbox Code Playgroud)
作为一项规则,我见过的主要用途是两个arg iter涉及将类似于C API的函数(隐式状态,没有迭代的概念)转换为迭代器.类似文件的对象是一个常见的例子,但它出现在其他库中,很难包装C API.您期望的模式可以在FindFirstFile/中看到,例如/ FindNextFile,其中资源被打开,每个调用都会提升内部状态并返回新值或标记变量(如NULLC中所示).将它包装在实现迭代器协议的类中通常是最好的,但是如果你必须自己做,虽然API是内置的C级,但是包装最终会减慢使用速度,其中两个arg iter,在C中实现好吧,可以避免额外的字节码执行费用.
其他示例涉及在循环期间更改的可变对象,例如,在bytearray中以相反顺序循环,仅在处理完成后删除该行:
>>> 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
Run Code Online (Sandbox Code Playgroud)
另一种情况是以渐进方式使用切片,例如,一种有效的(如果难以置信的丑陋)方式将可迭代分组为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
Run Code Online (Sandbox Code Playgroud)
另一个用途:将多个pickle对象写入一个文件,然后是一个sentinel值(None例如),所以当unpickling时,你可以使用这个成语而不是需要以某种方式记住pickle项目的数量,或者需要load反复调用直到EOFError:
with open('picklefile', 'rb') as f:
for obj in iter(pickle.Unpickler(f).load, None):
... process an object ...
Run Code Online (Sandbox Code Playgroud)
在多处理/多线程代码中,您(希望)会经常发现此构造用于轮询队列或管道。在标准库中,您还可以在以下位置找到它multiprocessing.Pool:
@staticmethod\ndef _handle_tasks(taskqueue, put, outqueue, pool, cache):\n thread = threading.current_thread()\n\n for taskseq, set_length in iter(taskqueue.get, None):\n task = None\n try:\n # iterating taskseq cannot fail\n for task in taskseq:\n ...\n else:\n util.debug(\'task handler got sentinel\')\nRun Code Online (Sandbox Code Playgroud)\n\n不久前,我看到了这篇博客文章,IMO 总结了它的iter(callable, sentinel)优点while True ... break:
\n\n通常,当我们迭代一个对象或直到某个条件发生时,我们会在第一行中了解循环的范围。例如,当阅读以 for book in books 开头的循环时,我们意识到我们\xe2\x80\x99正在迭代所有书籍。当我们看到一个以 while 而不是 Battery.empty() 开头的循环时,我们意识到循环的范围是只要我们还有电池即可。\n 当我们说 \xe2\x80\x9cDoforever\xe2\x80\ x9d(即,虽然 True),它\xe2\x80\x99s 显然这个范围是一个谎言。因此,它要求我们将这个想法牢记在心,并在代码的其余部分中搜索\xe2\x80\x99 将使我们摆脱困境的语句。我们进入循环的信息较少,因此可读性较差。
\n
| 归档时间: |
|
| 查看次数: |
3571 次 |
| 最近记录: |