2012-01-03 148 views
3

這是我在互聯網上找到的一些代碼,它沒有太多解釋。我只是好奇它是如何工作的。我不完全瞭解yield[s for s in subsets(S)]部分。任何有識之士將非常感謝!Python 3 - [s for s in subsets(S)] and yield

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) 

回答

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))來實現同樣的事情。當您想要對每個對象集合執行某些操作時,或者想要對其進行過濾時,都會使用列表推導。

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 
>>> 

可以使用發電機像一個迭代,因爲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')] 
相關問題