Python 3 - [s для s в подмножествах (S)] и выход - PullRequest
3 голосов
/ 03 января 2012

Это некоторый код, который я нашел в интернете, и он не имеет особых объяснений.Мне просто интересно, как это работает.Я не совсем понимаю часть 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)

Ответы [ 2 ]

4 голосов
/ 03 января 2012

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 голосов
/ 03 января 2012

Способ понять yield состоит в том, чтобы представить, что это просто оператор возврата с добавленным поворотом, что при следующем вызове функции выполнение продолжается с оператора 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')]
...