如何在创建生成器时评估Python生成器中的值,而不是在迭代它时?

时间:2016-08-09 17:32:15

标签: python django generator

以下是我的代码:

import itertools

i = itertools.chain()
for a in [1, 2, 3]:
    i = itertools.chain(i, (a for _ in range(2)))

print(list(i))
[3, 3, 3, 3, 3, 3]

在创建生成器时,有没有办法可以访问a的值,而不是在print语句中迭代它时?

我希望输出为[1,1,2,2,3,3],即创建生成器时a的值。

这是一个微不足道的问题,但在我的情况下,我在外循环中迭代1,000,000行,然后在内循环中为每个百万行生成8行,所以我热衷于保持它为生成器。

的Nb。用例是我在外循环中迭代一个表,为每一行创建子对象,将主键传递给子对象。数字非常大,所以我想构建生成器,然后在循环后批量插入(使用Django' s Model.objects.bulk_create(generator))。但是当我调用bulk_create时,主键始终设置为外循环中的最后一行。

gen = itertools.chain()
for id in ParentModel.objects.all().value_list('id', flat=True)):
    gen = itertools.chain(gen, (InnerModel(fk=id) for i in range(10000)))
InnerModel.objects.bulk_create(gen)

所有生成的InnerModel都指向列表中的最后一个OuterModel。

2 个答案:

答案 0 :(得分:2)

一种方法是重新构建代码以使用两个for genexp,以便id在需要时具有正确的值:

InnerModel.objects.bulk_create(
        InnerModel(fk=id) for id in ParentModel.objects.all().value_list('id', flat=True)
        for i in range(10000))

作为另一个好处,你不会得到你正在使用那些嵌套的chain构建的令人讨厌的堆栈溢出。

答案 1 :(得分:1)

如果你不介意将元组包装成lambda:

>>> import itertools
>>> i = itertools.chain()
>>> for a in [1, 2, 3]:
>>>     i = itertools.chain(i, (lambda x: (x for _ in range(2)))(a))
>>> print(list(i))
[1, 1, 2, 2, 3, 3]

想法是复制每次迭代的a的值。 lambda的论证可以做到这一点。在每次迭代中,创建局部变量x并使用a进行分配。