在列表理解中创建多个生成器

jul*_*e64 5 python list-comprehension generator

我试图将相同西装(颜色)的卡片组合在一起并在发生器内排名,并将这些发生器存储在列表理解中.

我提出的解决方案除了所有发生器包含完全相同的卡之外.知道为什么吗?

这是代码

deck=range(52)

gens=[(i for i in deck if i%13==v) for v in range(13)]
Run Code Online (Sandbox Code Playgroud)

基于此,我希望例如:

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


gens[10].next()
10
gens[10].next()
23
Run Code Online (Sandbox Code Playgroud)

但相反,我得到了

gens[1].next()
12

gens[1].next()
25

gens[1].next()
38
Run Code Online (Sandbox Code Playgroud)

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

Dou*_*gal 7

问题是v生成器表达式中的名称引用v列表推导中的该变量.因此,当您的生成器表达式实际运行的代码(当您调用时next),它会查看变量v并查看值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)]
Run Code Online (Sandbox Code Playgroud)

因为我们定义了一个函数,所以名称v可以存在于自己的命名环境中,因此保持不变.

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

 gens = [(lambda v: (i for i in deck if i % 13 == v))(v) for v in range(13)]
Run Code Online (Sandbox Code Playgroud)


aba*_*ert 5

如果将其转换为等效的嵌套循环,则可以更轻松地查看范围界定问题:

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

你最终得到13个生成器,所有生成器都绑定到v12 的相同值.

因此,此处的解决方案与任何其他范围问题中的解决方案相同:您需要使用其中的内容创建新范围v.最简单的方法是创建一个新函数:

gens = [(lambda x: (i for i in deck if i%13==x)(v) for v in range(13)]
Run Code Online (Sandbox Code Playgroud)