# 提高你的Python: 解释‘yield’和‘Generators（生成器）’

### 例子：有趣的素数

```def get_primes(input_list):
result_list = list()
for element in input_list:
if is_prime(element):
result_list.append()

return result_list

# 或者更好一些的...

def get_primes(input_list):
return (element for element in input_list if is_prime(element))

# 下面是 is_prime 的一种实现...

def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False```

#### 处理无限序列

```def get_primes(start):
for element in magical_infinite_range(start):
if is_prime(element):
return element```

```def solve_number_10():
# She *is* working on Project Euler #10, I knew it!
total = 2
for next_prime in get_primes(3):
if next_prime < 2000000:
total += next_prime
else:
print(total)
return```

## 走进生成器

(next()会操心如何调用生成器的__next__()方法)。既然生成器是一个迭代器，它可以被用在for循环中。

yield就是专门给生成器用的return(加上点小魔法)。

```>>> def simple_generator_function():
>>>    yield 1
>>>    yield 2
>>>    yield 3```

```>>> for value in simple_generator_function():
>>>     print(value)
1
2
3
>>> our_generator = simple_generator_function()
>>> next(our_generator)
1
>>> next(our_generator)
2
>>> next(our_generator)
3```

### 魔法?

```def get_primes(number):
while True:
if is_prime(number):
yield number
number += 1```

```>>> our_generator = simple_generator_function()
>>> for value in our_generator:
>>>     print(value)

>>> # 我们的生成器没有下一个值了...
>>> print(next(our_generator))
Traceback (most recent call last):
File "<ipython-input-13-7e48a609051a>", line 1, in <module>
next(our_generator)
StopIteration

>>> # 然而，我们总可以再创建一个生成器
>>> # 只需再次调用生成器函数即可

>>> new_generator = simple_generator_function()
>>> print(next(new_generator)) # 工作正常
1```

### 执行流程

```def solve_number_10():
# She *is* working on Project Euler #10, I knew it!
total = 2
for next_prime in get_primes(3):
if next_prime < 2000000:
total += next_prime
else:
print(total)
return```

1. 进入第三行的while循环
2. 停在if条件判断（3是素数）
3. 通过yield将3和执行控制权返回给solve_number_10

1. for循环得到返回值3
2. for循环将其赋给next_prime
3. total加上next_prime
4. for循环从get_primes请求下一个值

```def get_primes(number):
while True:
if is_prime(number):
yield number
number += 1 # <<<<<<<<<<```

## 更给力点

PEP 342中加入了将值传给生成器的支持。PEP 342加入了新的特性，能让生成器在单一语句中实现，生成一个值（像从前一样），接受一个值，或同时生成一个值并接受一个值。

```def print_successive_primes(iterations, base=10):
# 像普通函数一样，生成器函数可以接受一个参数

prime_generator = get_primes(base)
# 这里以后要加上点什么
for power in range(iterations):
# 这里以后要加上点什么

def get_primes(number):
while True:
if is_prime(number):
# 这里怎么写?```
get_primes的后几行需要着重解释。yield关键字返回number的值，而像 other = yield foo 这样的语句的意思是，"返回foo的值，这个值返回给调用者的同时，将other的值也设置为那个值"。你可以通过send方法来将一个值”发送“给生成器。
```def get_primes(number):
while True:
if is_prime(number):
number = yield number
number += 1```

```def print_successive_primes(iterations, base=10):
prime_generator = get_primes(base)
prime_generator.send(None)
for power in range(iterations):
print(prime_generator.send(base ** power))```

## 综述

```import random

def get_data():
"""返回0到9之间的3个随机数"""
return random.sample(range(10), 3)

def consume():
"""显示每次传入的整数列表的动态平均值"""
running_sum = 0
data_items_seen = 0

while True:
data = yield
data_items_seen += len(data)
running_sum += sum(data)
print('The running average is {}'.format(running_sum / float(data_items_seen)))

def produce(consumer):
"""产生序列集合，传递给消费函数（consumer）"""
while True:
data = get_data()
print('Produced {}'.format(data))
consumer.send(data)
yield

if __name__ == '__main__':
consumer = consume()
consumer.send(None)
producer = produce(consumer)

for _ in range(10):
print('Producing...')
next(producer)```

### 请谨记……

• generator是用来产生一系列值的
• yield则像是generator函数的返回结果
• yield唯一所做的另一件事就是保存一个generator函数的状态
• generator就是一个特殊类型的迭代器（iterator）
• 和迭代器相似，我们可以通过使用next()来从generator中获取下一个值
• 通过隐式地调用next()来忽略一些值