我做了这个功能:
def iter_intersperse(iterOver, injectItem, startWithIter = True):
for item in iterOver:
sendItem = (item, injectItem) if startWithIter else (injectItem, item)
yield sendItem
将项目散布在生成器中的项目之间。它用于一些 wxpython AddMany 调用,我想在大字典中的每个面板之间添加一个间隔符(所有间隔符大小相同)。它有效,但对于我想做的事情来说似乎有点矫枉过正,尽管它很小。
我已经考虑了一些我能想到的选项——创建一个与面板字典长度相同的间隔列表并压缩它们,这似乎更加矫枉过正。我想我可以用 set() True 或 False 等来做一个切换生成器,但我想不出如何让它工作。不久前有人告诉我,如果您要创建一个迭代函数,您可能不会想到已经有一些 itertool 可以做到这一点。我知道 Cycle 可以做到这一点,但它需要的代码与上面的函数一样多。
作为引用,我只想进行理解,但 AddMany 需要一个元组列表,因此我必须从列表或字典进行转换 - 这似乎也有点矫枉过正。
你能想出更优雅的方式吗?或者,如果不是,上面的代码是否尽可能高效?
最佳答案
我建议将 zip
与 itertools.repeat
一起使用。也许这对于内联来说很简单(大概你会知道顺序),但如果你想在函数中使用它,你也可以这样做:
def iter_intersperse(iterOver, injectItem, startWithIter = True):
if startWithIter:
return zip(iterOver, itertools.repeat(injectItem))
return zip(itertools.repeat(injectItem), iterOver)
如果您使用的是 Python 2,并且不需要 zip
返回的 list
,请改用 itertools.izip
。
编辑:因为您似乎想要交替,而不是元组,请尝试使用此生成器函数:
def iter_intersperse(iterOver, injectItem, startWithIter=True):
if startWithIter:
try:
yield next(iterOver)
except Stopiteration:
return
for item in iterOver:
yield injectItem
yield item
如果 startWithIter
为 True
,则最后不会生成 injectItem
的最后一个副本。如果您需要,请在函数末尾添加 if not startWithIter: YieldjectItem
。如果您选择是否需要尾部填充值与是否需要前导填充值不相关,您还可以考虑添加 stopWithIter
参数。
在所有当前和过去版本的 Python 中,您可以让 next
(如果迭代器为空)可能引发的 StopIteration
异常冒泡到调用方。之后PEP 479生效(在 3.5 和 3.6 中,如果您使用 from __future__ import Generator_stop
请求,在 3.7 中对所有人),但是,“泄漏”StopIteration
将转换为运行时错误
。因此,为了避免将来出现问题,我使用 try
/ except
对从生成器中 return
(这将引发一个新的 >StopIteration
外部范围内的异常)。
关于Python——生成器在迭代器之间散布值——我这样做正确吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29861537/