[英]How to take first element from iterator/generator and put it back in Python?
I would like to take first element from iterator, analyse it, then put it back and work with iterator as if it was not touched.我想从迭代器中取出第一个元素,对其进行分析,然后将其放回去并使用迭代器,就好像它没有被触及一样。
For now I wrote:现在我写道:
def prepend_iterator(element, it):
yield element
for element in it:
yield element
def peek_first(it):
first_element = next(it)
it = prepend_iterator(first_element, it)
return first_element, it
first_element, it = peek_first(it)
analyse(first_element)
continue_work(it)
it is possible to write better/shorter?有可能写得更好/更短吗?
Here is an example wit itertools.tee 这是一个示例itertools.tee
import itertools
def colors():
for color in ['red', 'green', 'blue']:
yield color
rgb = colors()
foo, bar = itertools.tee(rgb, 2)
#analize first element
first = next(foo)
print('first color is {}'.format(first))
# consume second tee
for color in bar:
print(color)
output 产量
first color is red
red
green
blue
Here I present a simple method that exploits concatenation of generators.在这里,我提出了一种利用生成器串联的简单方法。
import itertools
def concat_generators(*args: Iterable[Generator]) -> Generator:
r"""
Concat generators by yielding from first, second, ..., n-th
"""
for gen in args:
yield from gen
your_generator = (i for i in range(10))
first_element = next(your_generator)
# then you could do this
your_generator = concat_generators([first_element], your_generator)
# or this
your_generator = itertools.chain([first_element], your_generator)
Note this will only work if you're pushing back non- None
values. 注意这一点,如果你推背不只会工作None
价值。
If you implement your generator function (which is what you have) so that you care about the return value of yield
, you can "push back" on the generator (with .send()
): 如果实现生成器函数(即您拥有的函数),以便您关心yield
的返回值 ,则可以在生成器上“推回”(使用.send()
):
# Generator
def gen():
for val in range(10):
while True:
val = yield val
if val is None: break
# Calling code
pushed = false
f = gen()
for x in f:
print(x)
if x == 5:
print(f.send(5))
pushed = True
Here, you're printing both the x
from the for
loop and the return value of .send()
(if you call it). 在这里,您同时打印了for
循环中的x
和 .send()
的返回值(如果调用了它)。
0 1 2 3 4 5 5 # 5 appears twice because it was pushed back 6 7 8 9
This will only work let you push back once. 这只会让您后退一次。 If you want to push back more times than that, you do something like: 如果您想推回更多次,可以执行以下操作:
# Generator
def gen():
for val in range(10):
while True:
val = yield val
if val is None: break
# Generator Wrapper
class Pushable:
def __init__(self, g):
self.g = g
self._next = None
def send(self, x):
if self._next is not None:
raise RuntimeError("Can't pushback twice without pulling")
self._next = self.g.send(x)
def __iter__(self):
try:
while True:
# Have to clear self._next before yielding
if self._next is not None:
(tmp, self._next) = (self._next, None)
yield tmp
else:
yield next(self.g)
except StopIteration: return
# Calling code
num_pushed = 0
f = Pushable(gen())
for x in f:
print(x)
if (x == 5) and (num_pushed in [0,1,2]):
f.send(x)
num_pushed += 1
Produces: 生产:
0 1 2 3 4 5 # Pushed back (num_pushed = 0) 5 # Pushed back (num_pushed = 1) 5 # Pushed back (num_pushed = 2) 5 # Not pushed back 6 7 8 9
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.