我认为这是一个使用yield
的好时刻,但我被卡住了。
当某些内容失败时,我想将该项目发回发电机。我已经读到这是可能的,所以我真的很想使用我的第一台发电机。
states = ["IL", "NY", "NJ"]
for state in states:
ok = do something
if not ok:
*add state back as the first-to-deal with in the generator*
如何在这种情况下使用发电机?
答案 0 :(得分:3)
您可能指的是coroutine,它利用 yield表达式。它有点像这样:
def co_gen(li):
for x in li:
bad = yield x
if bad is not None:
print('ack! {}'.format(bad))
#other error handling
和(人为)用法:
states = ["IL", "NY", "NJ"]
gen = co_gen(states)
for x in gen:
print('processing state: {}'.format(x))
if x == 'NY':
y = gen.send('Boo, Yankees!')
print( 'processing state after error: {}'.format(y))
# processing state: IL
# processing state: NY
# ack! Boo, Yankees!
# processing state after error: NJ
突出点 - 正常yield
行为会将None
分配给bad
。如果它不是None,那么send
的东西就被编入了生成器。
当我们send
进入生成器时,恢复操作直到它到达下一个yield表达式。所以记住这一点 - 协程中的上述控制流程不是我称之为“标准”的,因为错误块中没有yield
完成。
这是一个比你正在谈论的更像一个协程:
def co_gen(li):
for x in li:
bad = yield x
while bad is not None:
print('error in generator: {}'.format(bad))
yield
bad = yield bad
gen = co_gen(states)
for x in gen:
print('processing state: {}'.format(x))
if random.choice([0,1]):
gen.send(x) #discard first yield
print( 'error: trying {} again'.format(x) )
# processing state: IL
# error in generator: IL
# error: trying IL again
# processing state: IL
# processing state: NY
# error in generator: NY
# error: trying NY again
# processing state: NY
# processing state: NJ
我们send
我们的状态回到了生成器,并且它一直在让它停止发送它。
答案 1 :(得分:0)
def ok(i):
from random import randint
return bool(randint(0,1))
def mygen(iterable):
def helper(iterable):
for i in iterable:
elem = yield i
if elem:
iterable.append(elem)
it = helper(iterable)
sendBack = False
while True:
try:
if sendBack:
print "Sending back {0}".format(i)
i = it.send(i)
else:
i = it.send(None)
if ok(i):
sendBack = False
yield i
else:
sendBack = True
except StopIteration:
break
x = range(10)
print list(mygen(x))
#Sending back 1
#Sending back 5
#Sending back 7
#Sending back 1
#Sending back 7
#[0, 2, 3, 4, 6, 8, 9, 5, 1, 7]
两个生成器,如果某些函数的返回值的计算结果为false,则返回该值。 (在这种情况下是随机的)。
答案 2 :(得分:0)
虽然可以使用常规生成器以及gen.send()
和sent_back = yield x
执行您所要求的操作,但您的代码将非常复杂。编写自己的iterator type可能更容易,它支持send
以外的方法来获取“已发回”项目:
class SendBackIter(object):
def __init__(self, iterable):
self.iterator = iter(iterable)
self.sent_back = []
def __iter__(self):
return self
def __next__(self):
if self.sent_back: # if the stack is not empty...
return self.sent_back.pop() # return the last item from the sent_back stack
return next(self.iterator) # otherwise return an item from our iterator
def send_back(self, obj):
self.sent_back.append(obj)
如果您只需要处理重复迭代中的项目,那么您可以使其更简单:
def RepeatableIter(object);
def __init__(self, iterable):
self.iterator = iter(iterable)
self.last_item = None
self.repeat = False # client code can set this to True to repeat the last value
def __iter__(self):
return self
def __next__(self):
if self.repeat:
self.repeat = False # only repeat once, by default
else:
self.last_item = next(self.iterator)
return self.last_item
以下是您可以使用最后一个版本的方法:
it = RepeatableIter(["foo", "bar", "baz"])
for item in it:
if is_not_ok(item):
it.repeat = True # this means we will get the same item on the next iteration
else:
do_something(item)