# КАК ПИСАТЬ СВОИ ГЕНЕРАТОРЫ

def very_simple_generator():
    yield 1
    yield 2
    yield 3

print(very_simple_generator())   # => <generator object very_simple_generator at 0x7fb21a745bf8>
                                 # Обратите внимание: в функции нет return-ов, а она что-то возвращает

print(list(very_simple_generator()))  # => [1, 2, 3]


# Питон выполняет функцию-генератор, пока не наткнётся на yield.
# После этого он останавливает функцию, прокидывает yield-нутый элемент в тело цикла
# и выполняет тело цикла. После этого функция продолжает выполняться с того места,
# где она остановилась в прошлый раз, до следующего yield-а.

def gen_with_prints():
    print("Yielding 1")
    yield 1
    print("Yielding 2")
    yield 2

for x in gen_with_prints():
    print(x)                     # Yielding 1
                                 # 1
                                 # Yielding 2
                                 # 2
                                 # 
     


# Как это можно использовать для того, чтобы генерировать список всех подмножеств
# рекурсивным перебором:

all_perms = []

def all_subsets(n, acc=[]):
    if n == 0:
        yield acc
    else:
        yield from all_subsets(n - 1, acc)
        acc.append(n)
        yield from all_subsets(n - 1, acc)
        acc.pop()
        

for subset in all_subsets(5):   # Функция в результате ведёт себя так, как будто она возвращает
    print(subset)               # плоский список всех перестановок (хотя на самом деле нет)

# yield from func(...) -- это синтаксический сахар для
#
#   for x in func(...):
#       yield x