def yrange(n): i = 0 while i < n: yield i i += 1每次执行 yield 语句时,函数都会生成一个新值。
>>> def foo(): ... print("begin") ... for i in range(3): ... print("before yield", i) ... yield i ... print("after yield", i) ... print("end") ... >>> f = foo() >>> next(f) begin before yield 0 0 >>> next(f) after yield 0 before yield 1 1 >>> next(f) after yield 1 before yield 2 2 >>> next(f) after yield 2 end Traceback (most recent call last): File "<pyshell#13>", line 1, in <module> next(f) StopIteration >>>生成器也是迭代器
f_2 = foo() for i in f_2: print(i) begin before yield 0 0 after yield 0 end before yield 1 1 after yield 1 end before yield 2 2 after yield 2 end
当一个函数包含 yield 时,Python 会自动实现一个迭代器,为我们应用所有需要的方法,比如 __iter__() 和 __next__(),所以生成器也能和迭代器有相同的功能,如下所示:
def yrange(): i = 1 while True: yield i i = i + 1 def squares(): for i in yrange(): yield i * i def take(n, seq): seq = iter(seq) result = [] try: for i in range(n): result.append(next(seq)) except StopIteration: pass return result print(take(5, squares())) # [1, 4, 9, 16, 25]接下来看一下如何使用生成器计算斐波那契数列:
def fib(n): if n <= 1: return 1 a, b = 0, 1 for _ in range(n): a, b = b, a + b yield a for i in fib(10): print(i, end=' ') # Result:1 1 2 3 5 8 13 21 34 55生成器推导式
generator_expressions = (x for x in range(10)) generator_expressions <generator object <genexpr> at 0x0000023F8BC51AF0> sum(generator_expressions) 45无限生成器
a = range(5) print(list(a)) [0, 1, 2, 3, 4]也可以这样做,使用如下生成器生成无限序列:
def infinite_sequence(): num = 0 while True: yield num num += 1运行此代码时,可以看到其运行非常快,可以通过 CTRL+C 来使得程序结束,如下:
def csv_reader(file_name): file = open(file_name) result = file.read().split("\n") return result csv_gen = csv_reader("some_file.csv") row_count = 0 for row in csv_gen: row_count += 1 print(f"Row count is {row_count}")我们的 csv_reader 函数将简单地将文件打开到内存中并读取所有行,然后它将行拆分并与文件数据形成一个数组。如果文件包含几千行,可能就会导致速度变慢,设置是内存被占满。
def csv_reader(file_name): for row in open(file_name, "r"): yield row读取文件内容
def readfiles(filenames): for f in filenames: for line in open(f): yield line def grep(pattern, lines): return (line for line in lines if pattern in line) def printlines(lines): for line in lines: print(line, end="") def main(pattern, filenames): lines = readfiles(filenames) lines = grep(pattern, lines) printlines(lines)高级生成器用法
def isPrime(n): if n < 2 or n % 1 > 0: return False elif n == 2 or n == 3: return True for x in range(2, int(n**0.5) + 1): if n % x == 0: return False return True def getPrimes(): value = 0 while True: if isPrime(value): i = yield value if i is not None: value = i value += 1然后我们调用 send() 函数,这个函数会向生成器 prime_gen 传入一个值,然后从这个值开始计算下一个素数的值:
prime_gen = getPrimes() print(next(prime_gen)) print(prime_gen.send(1000)) print(next(prime_gen))可以看到如下结果:
prime_gen = getPrimes() for x in prime_gen: if x > 20: prime_gen.throw(ValueError, "I think it was enough!") print(x)运行该代码,得到结果如下:
prime_gen = getPrimes() for x in prime_gen: if x > 20: prime_gen.close() print(x)运行结果如下图: