Python初学者被一行复杂代码弄糊涂
我大致明白这段代码的意思,它是用来生成排列的。不过,我想知道具体在返回语句中发生了什么。
def perm(l):
sz = len(l)
print (l)
if sz <= 1:
print ('sz <= 1')
return [l]
return [p[:i]+[l[0]]+p[i:] for i in range(sz) for p in perm(l[1:])]
5 个回答
1
看看这个:
>>> l = [1, 2, 3, 4, 5, 6]
>>> p = l[1:]
>>> p
[2, 3, 4, 5, 6]
>>> i = 3
>>> p[:i]
[2, 3, 4]
>>> p[i:]
[5, 6]
>>> p[:i]+[l[0]]+p[i:]
[2, 3, 4, 1, 5, 6]
>>>
所以,事情是这样的,p
代表的是去掉第一个元素后的列表l[1:]
的所有排列组合。接下来,i
是range(sz)
,这意味着它的值会从0变化到列表l
的长度。这样就会把p
分成两个列表,包含所有可能的大小(比如0和sz,1和sz-1,2和sz-2,等等),然后把l
的第一个元素,也就是没有被排列的那个元素,放在这两个列表之间。
4
这个返回语句使用了列表推导式。如果把它放到实际的循环里,会更容易理解:
value = []
for i in range(sz):
# call this function using all but the first item in l
for p in perm(l[1:]):
# now place the first item in l between index i-1 and index i in p
value.append(p[:i] + [l[0]] + p[i:])
return value
10
这个 return
语句返回的是一个列表推导式,里面的每个元素都是把 l
的第一个元素放到 p
的每个位置上,从第一个位置到最后一个位置。p
是一个列表的列表,它是通过递归调用 perm
得到的,这个调用排除了 l
的第一个元素,因此会对所有其他元素进行各种可能的排列。
如果你不理解递归,这个概念确实不容易解释;-)。不过,如果你不理解列表推导式,那就简单多了——这个 return
的意思其实可以用下面的方式来表达:
result = []
for i in range(sz):
for p in perm(l[1:]):
result.append(p[:i]+[l[0]]+p[i:])
return result
这也显示了这段代码的低效:它递归调用 perm
总共 sz
次,显然这样做是没有必要的。更好的做法是直接交换两个 for
循环的位置:
result = []
for p in perm(l[1:]):
for i in range(sz):
result.append(p[:i]+[l[0]]+p[i:])
return result
而这个更好的代码的等价形式,就是把两个 for
子句的位置互换的列表推导式:
return [p[:i]+[l[0]]+p[i:] for p in perm(l[1:]) for i in range(sz)]