这是我在互联网上找到的一些代码,但没有太多解释。我只是好奇它是如何工作的。我不完全理解yield
和[s for s in subsets(S)]
部分。任何见解都会非常感激!
def subsets(aList):
if aList ==[]: # base case
yield []
else:
first = aList[0]
rest = aList[1:]
for ss in subsets(rest): # include first or don't in each
yield ss # subset of rest
yield [first]+ss
print ("\n testing subsets")
S = ['A','B','C','D','E']
ss = [s for s in subsets(S)]
print ("The subsets of",S,"are:")
print (ss)
答案 0 :(得分:4)
subsets
是一个生成器:当你调用它时,你创建一个可以迭代的对象。每次迭代从中请求另一个值时,它将运行到下一个yield
语句,并生成该值。它也是递归的,所以当你用五个项目运行它时,它会在最后四个项目中调用它,依此类推。
因此,如果它传递['A']
,它会创建第二个生成器,它会传递一个空列表[]
。这只会产生一个空列表,然后完成。主生成器将接收它,产生它(yield ss
),然后yield [first]+ss
,它将是['A']
。总结果:[[], ['A']]
[s for s in subsets(S)]
是列表理解。它相当于:
ss = []
for s in subsets(S)
ss.append(s)
在这种情况下,它有点多余 - 您可以list(subsets(S))
来实现相同的目标。如果要对每个对象集合执行某些操作,或者要对其进行过滤,则使用列表推导。
答案 1 :(得分:2)
理解yield
的方法是想象它只是一个return语句,附加的扭曲是下次调用该函数时,从yield语句继续执行。如果没有剩余产量,则会引发StopIteration
异常。
一个更简单的例子应该清除:
>>> def foo():
... for i in range(3):
... yield i
...
>>> x = foo()
>>> x
<generator object foo at 0x7f0cd5c30780>
>>> x.next()
0
>>> x.next()
1
>>> x.next()
2
>>> x.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
您可以像使用iterable一样使用生成器,因为for
循环只是在内部捕获并处理StopIteration
异常:
>>> x = foo()
>>> for i in x:
... print i
...
0
1
2
>>>
至于获取子集,有一种更简单的方法!
看看下面的食谱:
>>> from itertools import chain, combinations
>>>
>>> def powerset(iterable):
... s = list(iterable)
... return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
>>>
>>> S = ['A','B','C']
>>> list(powerset(S))
[(),
('A',),
('B',),
('C',),
('A', 'B'),
('A', 'C'),
('B', 'C'),
('A', 'B', 'C')]