首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >复制生成器

复制生成器
EN

Stack Overflow用户
提问于 2015-04-23 22:56:02
回答 2查看 15.9K关注 0票数 15

假设我有一台这样的发电机

代码语言:javascript
复制
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

现在让我们假设我知道

代码语言:javascript
复制
>>> g = gen()
>>> g.next()
>>> g.send(42)
a_ =  43
43

现在我们计算了a_。现在我想像这样克隆我的发电机。

代码语言:javascript
复制
>>> newG = clonify(g)
>>> newG.send(7)
b = 7
a_ = 43
7

但我最初的g仍然有效。

代码语言:javascript
复制
>>> g.send(11)
b = 11
a_ = 43
11

具体来说,clonify获取生成器的状态,并复制它。我可以重新设置我的生成器,使其像旧的一样,但这需要计算a_。还请注意,我不想对生成器进行广泛的修改。理想情况下,我可以从库中获取生成器对象并对其进行clonify

注意:itertools.tee 不能工作,因为它不处理发送.

注意:我只关心在函数中放置yield 语句所创建的生成器.

EN

回答 2

Stack Overflow用户

发布于 2015-04-23 23:12:00

一般情况下你不能。然而,如果你为一些昂贵的手术提供参数,为什么不把操作举出来,建立一个发电机工厂呢?

代码语言:javascript
复制
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

然后,您可以从返回的对象创建任意数量的生成器:

代码语言:javascript
复制
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]
票数 2
EN

Stack Overflow用户

发布于 2020-09-18 23:41:37

虽然技术上没有返回生成器,但如果您不介意完全扩展序列的话:

代码语言:javascript
复制
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'>

如果您的函数很昂贵,那么可以考虑使用强权bpathos.multiprocessing。Joblib具有更简单的语法,并在幕后处理池管理,但只支持批处理。Pathos迫使您手动管理和关闭您的ProcessPools,但也可以作为pool.imap()作为一个返回生成器的pool.uimap()函数。

代码语言:javascript
复制
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()

理论上,您可以将其设置为在一个单独的线程中运行,并传入两个队列对象,这些对象可以独立读取,并且可以像这个答案中建议的那样保持生成器的行为:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29835784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档