生成器和高级函数-filter、map等

yield和生成器

范例(生成斐波那契數列)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 方案一
def fab(max):
n, a, b = 0, 0, 1
L = []
while n < max:
L.append(b)
a, b = b, a + b
n = n + 1
return L
# 通过 iterable 对象来迭代
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
>>> for n in Fab(5):
... print n
...
1
1
2
3
5
# 使用 yield
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
>>> for n in fab(5):
... print n
...
1
1
2
3
5

yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

1
2
3
4
5
6
7
8
9
10
11
12
# 使用 isgeneratorfunction 判断
>>> from inspect import isgeneratorfunction
>>> isgeneratorfunction(fab)
True
# 类的定义和类的实例
# 要注意区分 fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别:
>>> import types
>>> isinstance(fab, types.GeneratorType)
False
>>> isinstance(fab(5), types.GeneratorType)
True

在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。

1
2
3
4
5
6
7
8
9
10
# 文件读取
def read_file(fpath):
BLOCK_SIZE = 1024
with open(fpath, 'rb') as f:
while True:
block = f.read(BLOCK_SIZE)
if block:
yield block
else:
return

生成器在单一语句中实现,生成一个值,接受一个值,或同时生成一个值并接受一个值。

1
2
3
4
5
6
7
8
9
10
11
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))

yield关键字返回number的值,而像 other = yield foo 这样的语句的意思是,”返回foo的值,这个值返回给调用者的同时,将other的值也设置为那个值”。你可以通过send方法来将一个值”发送“给生成器。send在发送数据给生成器的同时还返回生成器通过yield生成的值。当你用send来“启动”一个生成器时(就是从生成器函数的第一行代码执行到第一个yield语句的位置),你必须发送None。这不难理解,根据刚才的描述,生成器还没有走到第一个yield语句,如果我们发生一个真实的值,这时是没有人去“接收”它的。

属性(properties)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Square(object):
"""A square with two properties: a writable area and a read-only perimeter.
To use:
>>> sq = Square(3)
>>> sq.area
9
>>> sq.perimeter
12
>>> sq.area = 16
>>> sq.side
4
>>> sq.perimeter
16
"""
def __init__(self, side):
self.side = side
def __get_area(self):
"""Calculates the 'area' property."""
return self.side ** 2
def ___get_area(self):
"""Indirect accessor for 'area' property."""
return self.__get_area()
def __set_area(self, area):
"""Sets the 'area' property."""
self.side = math.sqrt(area)
def ___set_area(self, area):
"""Indirect setter for 'area' property."""
self._SetArea(area)
area = property(___get_area, ___set_area,
doc="""Gets or sets the area of the square.""")
@property
def perimeter(self):
return self.side * 4