# Generator

To put it simply, the generator function feels like a `return` can be created in the middle of the function. However, the feature is that it does not end even if you do something like `return`. Also, I will return them one by one, so I don't use much memory. I will also explain the sub-generator added in python3. Code created this time: https://github.com/KodairaTomonori/Qiita/tree/master/default_module/syntax Actually use `yield` instead of` return`. First of all, simply from the `counter` and` fibonatti` sequence generation functions that count numbers

## Basic usage (yield,. \ _ \ _ Next__ (), .close ())

#### `counter_and_fibonati.py`

``````
def counter():
num = 0
while True:
yield num
num += 1

def fibonatti():
now = 0
next_num = 1
while True:
yield now
now, next_num = next_num, now + next_num

if __name__ == '__main__':
count = counter()
print('print 0-3, for i in count')
for i in count:
print(i, end=', ')
if i >= 3:
print()
break
print('next_count, count.__next__()')
print(count.__next__())
print('print 5-7, for i in count')
for i in count:
print(i, end=', ')
if i >= 7:
count.close()
print()
print('print fibonatti')
for i in fibonatti():
if i > 100: break
print(i, end=', ')
print(i)
``````

### output

print 0-3, for i in count 0, 1, 2, 3, next_count, count.__next__() 4 print 5-7, for i in count 5, 6, 7, print fibonatti 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144

### Commentary

First, the `counter` function is simple, starting at` num = 0` and entering an infinite loop of `while`. Returns `num` with` yield num` for each loop. Then was `counter` called? Sometimes `num + 1` and then` yield num` is returned. Each time it is called, a `+ 1` value is returned. When using it, it is written in the place of `main`, but if you put it in the` for` statement, it will return the value `0,1,2,3` in sequence for each loop.

You can save its state (`num`) by defining it as a variable with`count = counter ()`.

Using `count.__next__ ()` will return the next number, that is, `4`.

The following for statement also adds one by one and returns it as before. However, unlike before, the state of `count` stops at` num = 4`, so this loop starts at `5`. So, at the end, when it became `7` or more, I did`count.close ()`to end the loop.

If you use `.close ()`, you can exit the `for` statement and lose the function as a generator of` count`. After this, spit out `count.__next__ ()` and `StopIteration`.

The `fibonatti` is almost the same, so there is no particular problem. In this case, the generator is placed directly with `fibonatti ()`, so after exiting the `for` statement, the generator where` now, next_num` is stored will go somewhere.

The fact that it can be turned with a `for` statement can be made into a` list` by enclosing it in `list ()`, but in that case, if you do not set a limit in the generator function, you will die in an infinite loop, so be careful.

## When you want to give an argument each time you call

You can pass arguments each time with `.send (x)`. `.send (x)` gives` x` to the position of `yield`, so you have to execute`.__ next__ ()`once.

#### `generator_send.`

``````

def generator(step):
val = 0
prev = 0
while True:
if step == None:
step = prev
prev = step
val += step
step = yield val

if __name__ == '__main__':
gen = generator(0)
print(gen.__next__(), end=', ')
for i in [1,2,3,4,5,6]:
print(gen.send(i) , end=', ')
print()
``````

### output

0, 1, 3, 6, 10, 15, 21,

### Commentary

The `generator` function is a program that adds the received argument` step` to `val`. First, set the `generator (0)` initial value to 0. Then use `.__next__ ()` to go to `step = yield val`. Then `0` will be returned. Then enter the for statement and turn from `1 to 6`. When `gen.send (i)` is executed, ʻi` is entered at the previous` step = yield val`. In other words, if you do `gen.send (i)`, you get `step = i`. I will loop like that. Here, if you do `.__ next __ ()`without using`.send ()`, you will get `step = None`.

# New in python3: Subgenerator

The sub-generator will execute the generator if you do `yield from generator`. `generator` is a generator function. This makes recursion very convenient.

A sample program for generating permutations containing the same is explained.

#### `ex_permutation.py`

``````
def ex_permutation(iterable, now_list=[]):
if not iterable:
yield now_list
return
for i in [iterable.index(i) for i in set(iterable) ]:
yield from permutation(iterable[:i] + iterable[i+1:], now_list + [iterable[i] ])

if __name__ == '__main__':
permu = ex_permutation([2,2,3])
for i in permu:
print(i)
``````

### output

[2, 2, 3] [2, 3, 2] [3, 2, 2]

## Commentary

I don't care what's inside, but I'm just doing it recursively using `set ()` so that it doesn't get covered. So you can write recursively with `yield from`. Finally, it returns `now_list` when the contents of ʻiterable` are empty. I don't know what it is, but it's convenient! It seems to be confusing without this.

# Summary

You can return a value in the middle of the function with `yield`. You can end the generator function with `.close ()`. Do the following with `.__next__ ()` You can pass a value with `.send ()` `yield from` is convenient.