Python:单行笛卡尔积for循环

4
你知道你可以做这个吗?
>>> [(x,y) for x in xrange(2) for y in xrange(5)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]

“很整洁。是否有for循环版本,或者只能用列表推导式实现?”
“编辑:我认为我的问题被误解了。我想知道是否有特殊的语法来实现这个:”
for x in xrange(2) <AND> y in xrange(5):
    print "do stuff here"
    print "which doesn't fit into a list comprehension"
    print "like printing x and y cause print is a statement", x, y

我可以做这个,但似乎有点重复。
for x,y in ((x,y) for x in xrange(2) for y in xrange(5)):
    print x, y

3
不行,那只适用于列表推导式。 - rubik
1
+1 Rubik是正确的,这不是支持的语法。 - samplebias
@samplebias:啊,如果能够接受评论作为答案就好了。 - Claudiu
2个回答

10

虽然没有你想要的语法,但是有itertools.product

>>> import itertools
>>> for x, y in itertools.product([1,2,3,4], [5,6,7,8]): print x, y
... 
1 5
1 6
1 7
1 8
[ ... and so on ... ]

5

这是一个等价的、更加紧凑的版本:

def values():
    for x in xrange(2):
        for y in xrange(5):
            yield (x, y)
list(values())

更新: 要比较两者的字节码,请执行以下操作:

import dis
print dis.dis(values)   # above function

gen = ((x,y) for x in xrange(2) for y in xrange(5))
print dis.dis(gen.gi_code)

这是一个精确的等价吗?(Python是否实际为每个列表推导式创建生成器?)否则,输出当然会相同。 - Claudiu
是的,虽然我认为生成器更有效率,但字节码非常接近。 - samplebias
当然,它并没有为每个列表推导式定义一个完整的一次性生成器。它也不会将其展开成Python级别的循环。但是这些实现细节并不重要,这个例子定义生成器的事实也不重要。重要的是循环的嵌套方式。(编辑:挑剔地说,OP使用的是列表推导式,它使用特殊的字节码实现!) - user395760
@delnan:啊,这取决于问题的层次。 我同意最初看起来好像我不知道嵌套是什么,但对我来说它很明显-因此,以输出的等价性为前提,我正在寻找是否有更多关于您答案的信息。 靠查看字节码来解决问题真是个好技巧! - Claudiu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接