如何在Python中简化循环金字塔?

在实体力学中,我经常使用Python并编写类似于以下内容的代码:


for i in range(3):

    for j in range(3):

        for k in range(3):

            for l in range(3):

                # do stuff

我经常这样做,以至于我开始怀疑是否有更简洁的方法可以做到这一点。当前代码的缺点是:如果我遵守PEP8,那么我就不能超过每行79个字符的限制,并且没有太多的空间,特别是如果这又是一个类的函数。


慕丝7291255
浏览 742回答 3
3回答

郎朗坤

根据您要执行的操作,您可以使用该itertools模块来最大程度地减少for循环(或zip)。在这种情况下,itertools.product将创建您使用4个循环完成的工作:>>> list(product(range(3),repeat=4))[(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 1, 0), (0, 0, 1, 1), (0, 0, 1, 2), (0, 0, 2, 0), (0, 0, 2, 1), (0, 0, 2, 2), (0, 1, 0, 0), (0, 1, 0, 1), (0, 1, 0, 2), (0, 1, 1, 0), (0, 1, 1, 1), (0, 1, 1, 2), (0, 1, 2, 0), (0, 1, 2, 1), (0, 1, 2, 2), (0, 2, 0, 0), (0, 2, 0, 1), (0, 2, 0, 2), (0, 2, 1, 0), (0, 2, 1, 1), (0, 2, 1, 2), (0, 2, 2, 0), (0, 2, 2, 1), (0, 2, 2, 2), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 0, 2), (1, 0, 1, 0), (1, 0, 1, 1), (1, 0, 1, 2), (1, 0, 2, 0), (1, 0, 2, 1), (1, 0, 2, 2), (1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 0, 2), (1, 1, 1, 0), (1, 1, 1, 1), (1, 1, 1, 2), (1, 1, 2, 0), (1, 1, 2, 1), (1, 1, 2, 2), (1, 2, 0, 0), (1, 2, 0, 1), (1, 2, 0, 2), (1, 2, 1, 0), (1, 2, 1, 1), (1, 2, 1, 2), (1, 2, 2, 0), (1, 2, 2, 1), (1, 2, 2, 2), (2, 0, 0, 0), (2, 0, 0, 1), (2, 0, 0, 2), (2, 0, 1, 0), (2, 0, 1, 1), (2, 0, 1, 2), (2, 0, 2, 0), (2, 0, 2, 1), (2, 0, 2, 2), (2, 1, 0, 0), (2, 1, 0, 1), (2, 1, 0, 2), (2, 1, 1, 0), (2, 1, 1, 1), (2, 1, 1, 2), (2, 1, 2, 0), (2, 1, 2, 1), (2, 1, 2, 2), (2, 2, 0, 0), (2, 2, 0, 1), (2, 2, 0, 2), (2, 2, 1, 0), (2, 2, 1, 1), (2, 2, 1, 2), (2, 2, 2, 0), (2, 2, 2, 1), (2, 2, 2, 2)]在您的代码中,您可以执行以下操作:for i,j,k,l in product(range(3),repeat=4):    #do stuff此函数等效于以下代码,不同之处在于实际实现不会在内存中建立中间结果:def product(*args, **kwds):    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111    pools = map(tuple, args) * kwds.get('repeat', 1)    result = [[]]    for pool in pools:        result = [x+[y] for x in result for y in pool]    for prod in result:        yield tuple(prod)编辑:正如@ PeterE在评论中所说,product()即使范围的长度不同,也可以使用:product(range(3),range(4),['a','b','c'] ,some_other_iterable)

慕尼黑的夜晚无繁华

使用的想法itertools.product是一个好主意。这是一种更通用的方法,将支持各种大小的范围。from itertools import productdef product_of_ranges(*ns):    for t in product(*map(range, ns)):        yield tfor i, j, k in product_of_ranges(4, 2, 3):    # do stuff

繁华开满天机

它不会更加简洁,因为它将花费您一个生成器函数,但是至少您不会被PEP8所困扰:def tup4(n):&nbsp; &nbsp; for i in range(n):&nbsp; &nbsp; &nbsp; &nbsp; for j in range(n):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for k in range(n):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for l in range(n):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield (i, j, k, l)for (i, j, k, l) in tup4(3):&nbsp; &nbsp; # do your stuff(在python 2.x中,您应该使用xrange而不是range在generator函数中)编辑:当金字塔的深度已知时,上述方法应该很好。但是您也可以通过这种方式生成通用生成器,而无需任何外部模块:def tup(n, m):&nbsp; &nbsp; """ Generate all different tuples of size n consisting of integers < m """&nbsp; &nbsp; l = [ 0 for i in range(n)]&nbsp; &nbsp; def step(i):&nbsp; &nbsp; &nbsp; &nbsp; if i == n : raise StopIteration()&nbsp; &nbsp; &nbsp; &nbsp; l[i] += 1&nbsp; &nbsp; &nbsp; &nbsp; if l[i] == m:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l[i] = 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; step(i+ 1)&nbsp; &nbsp; while True:&nbsp; &nbsp; &nbsp; &nbsp; yield tuple(l)&nbsp; &nbsp; &nbsp; &nbsp; step(0)for (l, k, j, i) in tup(4, 3):&nbsp; &nbsp; # do your stuff(我用过,(l, k, j, i)因为在上面的生成器中,第一个索引首先变化)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python