python中的复杂生成器

python中的复杂生成器,python,language-agnostic,generator,Python,Language Agnostic,Generator,我有一个长期运行的任务,必须由外部代码指导。但是外部代码需要有关此任务的一些信息。这是我的自制示例: def longtask(self): yield self.get_step_length(1) for x in self.perform_step(1): ... yield x.id yield self.get_step_length(2) for x in self.perform_step(2): .

我有一个长期运行的任务,必须由外部代码指导。但是外部代码需要有关此任务的一些信息。这是我的自制示例:

def longtask(self):
    yield self.get_step_length(1)
    for x in self.perform_step(1):
        ...
        yield x.id

    yield self.get_step_length(2)
    for x in self.perform_step(2):
        ...
        yield x.value

...
# call site
generator = self.longtask()
step1len = generator.Next()
step1pb = ProgressBar('Step 1', step1len)
# pull only step 1 items
for index, id in itertools.izip(xrange(0, step1len), generator):
    step1pb.update(index)
    ...do something with id

step2len = generator.Next()
step2pb = ProgressBar('Step 2', step1len)
# pull only step 1 items
for index, value in itertools.izip(xrange(0, step1len), generator):
    step2pb.update(index)
    ... do something other with value

在python中使用如此复杂的生成器协议是正确的,还是我需要重构这段代码?

我会将其重构为返回单独的生成器;可以使用嵌套函数:

def longtask(self):
    def step_generator(step):
        for x in self.perform_step(step):
            ...
            yield x.id

    yield step_length_1, step_one_generator(1)
    yield step_length_2, step_one_generator(2)

generators = self.longtask()
for counter, (steplength, stepgen) in enumerate(generators):
    ProgressBar('Step %d' % counter, steplength)
    for index, value in enumerate(stepgen):
        # ....

现在,您还可以使用
enumerate()
函数向项目添加数字;这比将
xrange()
和生成器压缩在一起可读性好得多。

我认为这里没有“对”或“错”。对我来说,这个例子看起来合理,但有点复杂。如果不了解上下文以及您当初选择此设计的原因,就很难提出建议。使用此设计的原因是,某些信息很容易从正在运行的流程中检索,而不是分离。例如,process可以创建数据库游标,用于获取一些附加信息。但是,生成器中的第二个循环生成
x.value
,因此我认为它们没有那么相似。@poke:您也可以使用多个嵌套函数。