假设我有一台这样的发电机
def gen():
a = yield "Hello World"
a_ = a + 1 #Imagine that on my computer "+ 1" is an expensive operation
print "a_ = ", a_
b = yield a_
print "b =", b
print "a_ =", a_
yield b现在让我们假设我知道
>>> g = gen()
>>> g.next()
>>> g.send(42)
a_ = 43
43现在我们计算了a_。现在我想像这样克隆我的发电机。
>>> newG = clonify(g)
>>> newG.send(7)
b = 7
a_ = 43
7但我最初的g仍然有效。
>>> g.send(11)
b = 11
a_ = 43
11具体来说,clonify获取生成器的状态,并复制它。我可以重新设置我的生成器,使其像旧的一样,但这需要计算a_。还请注意,我不想对生成器进行广泛的修改。理想情况下,我可以从库中获取生成器对象并对其进行clonify。
注意:itertools.tee 不能工作,因为它不处理发送.
注意:我只关心在函数中放置yield 语句所创建的生成器.
发布于 2015-04-23 23:12:00
一般情况下你不能。然而,如果你为一些昂贵的手术提供参数,为什么不把操作举出来,建立一个发电机工厂呢?
def make_gen(a):
a_ = [a + 1] # Perform expensive calculation
def gen(a_=a_):
while True:
print "a_ = ", a_
a_[0] = yield a_[0]
return gen然后,您可以从返回的对象创建任意数量的生成器:
gen = make_gen(42)
g = gen()
g.send(None)
# a_ = [43]
g.send(7)
# a_ = [7]
new_g = gen()
new_g.send(None)
# a_ = [7]发布于 2020-09-18 23:41:37
虽然技术上没有返回生成器,但如果您不介意完全扩展序列的话:
source = ( x**2 for x in range(10) )
source1, source2 = zip(*( (s,s) for s in source ))
>>> print( source1, type(source1) )
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81) <class 'tuple'>
>>> print( source2, type(source2) )
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81) <class 'tuple'>如果您的函数很昂贵,那么可以考虑使用强权b或pathos.multiprocessing。Joblib具有更简单的语法,并在幕后处理池管理,但只支持批处理。Pathos迫使您手动管理和关闭您的ProcessPools,但也可以作为pool.imap()作为一个返回生成器的pool.uimap()函数。
from pathos.multiprocessing import ProcessPool
pool = ProcessPool(ncpus=os.cpu_count())
try:
def expensive(x): return x**2
source = range(10)
results = pool.imap(expensive, source)
for result in results:
print(result)
except KeyboardInterrupt: pass
except: pass
finally:
pool.terminate()理论上,您可以将其设置为在一个单独的线程中运行,并传入两个队列对象,这些对象可以独立读取,并且可以像这个答案中建议的那样保持生成器的行为:
https://stackoverflow.com/questions/29835784
复制相似问题