# Yield From

## Chain iterable using `yield from`

No argument that generators are crazy useful.

However, writing generator functions can get messy beyond yielding one sequence.

Consider this function:

```
def range_then_exp(N):
for i in range(N):
yield i
for i in (x**2 for x in range(N)):
yield i
```

For a given `N`

, this yields the numbers 0 to N, then their squares.

`list(range_then_exp(5))`

```
[0, 1, 2, 3, 4, 0, 1, 4, 9, 16]
```

However, a much cleaner way to write that is using `yield from`

.

```
def range_then_exp(N):
yield from range(N)
yield from (x**2 for x in range(N))
```

`list(range_then_exp(5))`

```
[0, 1, 2, 3, 4, 0, 1, 4, 9, 16]
```

## More practical Example

Say you’re playing some table-top game and find yourself doing a lot of dice rolling.

We could use this to make generic functions.

```
import numpy as np
def roll_die(numFaces):
return np.random.randint(1, numFaces+1)
def multiple_dice(numDice, diceFaces):
'''Takes a sequence of [numDice]d20 rolls'''
yield from (roll_die(diceFaces) for _ in range(numDice))
```

```
def attack_rolls(numEnemies):
return [val for val in multiple_dice(numEnemies, diceFaces=20)]
def damage_rolls(numEnemies):
'''Assuming a greataxe and +2 str!'''
return [val+2 for val in multiple_dice(numEnemies, diceFaces=12)]
```

`attack_rolls(5)`

```
[13, 5, 9, 17, 4]
```

`damage_rolls(5)`

```
[10, 4, 4, 6, 6]
```

Neat!

And if you’re feeling especally lazy…

```
def roll_for_me(numEnemies):
return [(atk, dmg) for (atk, dmg) in zip(attack_rolls(numEnemies), damage_rolls(numEnemies))]
```

`roll_for_me(5)`

```
[(3, 10), (13, 4), (2, 9), (7, 4), (9, 10)]
```