6

我正在尝试将相同套装(颜色)的卡片分组并在生成器中排名并将这些生成器存储在列表理解中。

除了所有生成器都包含完全相同的卡片这一事实之外,我想出的解决方案就是这样做的。知道为什么吗?

这是代码

deck=range(52)

gens=[(i for i in deck if i%13==v) for v in range(13)]

基于此,我期望例如:

gens[1].next()
1
gens[1].next()
14


gens[10].next()
10
gens[10].next()
23

但相反我得到

gens[1].next()
12

gens[1].next()
25

gens[1].next()
38

并且列表中的所有生成器都返回相同的结果..

4

2 回答 2

8

问题是v生成器表达式中的名称指v的是列表理解中的该变量。因此,当您的生成器表达式实际运行的代码时(当您调用 时next),它会查看变量v并查看 value 12,无论v您创建生成器时的值是什么。

一种解决方法:

deck = range(52)

def select_kth(v):
    return (i for i in deck if i % 13 == v)

gens = [select_kth(v) for v in range(13)]

因为我们定义了一个函数,所以名称v可以存在于它自己的命名环境中,因此不会被修改。

如果你真的想要,你可以在一行中做到这一点:

 gens = [(lambda v: (i for i in deck if i % 13 == v))(v) for v in range(13)]
于 2013-04-03T19:09:31.810 回答
5

如果你把它变成等效的嵌套循环,你可以更容易地看到范围问题:

gens = []
for v in range(13):
    def gen():
        for i in deck:
            if i%13 == v:
                yield i
    gens.append(gen())

你最终会得到 13 个生成器,它们都绑定到相同的值v12。

因此,这里的解决方案与任何其他范围问题的解决方案相同:您需要在其中创建一个新范围v。最简单的方法是创建一个新函数:

gens = [(lambda x: (i for i in deck if i%13==x)(v) for v in range(13)]
于 2013-04-03T19:11:10.980 回答