python基础学习(四)-- 生成器(generator)
# 通过列表生成式 可以直接创建一个列表 但是 收到内存限制 列表容量肯定是有限的 而且 创建一个包含100万个元素的列表,不仅会占用很大的内存 如果我们只需要使用前些个元素 那后面的元素占用的空间就白费了 # 如果列表元素可以按照某种算法算出来, 并在循环的过程中不断推算出后续的元素,这样就不必创建完整的list 从而节省大量的空间, python中 这样一边循环一边计算的机制 称之为生成器 即generator # 创建一个generator的方法: # 一 只要吧列表生成式的【】改为() 就创建了一个generator print([x * x for x in range(11)]) print((x * x for x in range(11))) # 两者仅有的区别就是最外层的【】和() 前者是一个list 而后者就是一个generator # generator 可以通过next()函数获得generator的下一个返回值 在没有更多的元素时 会抛出StopIteration错误 不过一直使用next()调用有些变态 正确方法是使用for循环 因为generator也是可迭代对象 for n in (x * x for x in range(11)): print(n) # 所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。 # 比如,著名的斐波拉契数列(Fibonacci),***除第一个和第二个数外,任意一个数都可由前两个数相加得到*****,斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易: def fib(m): n, a, b = 0, 0, 1 while n < m: print(b) a, b = b, a + b n = n + 1 return 'done' fib(6) # 其实这里的fib函数已经很接近generator。要把fib函数变为generator,只需要吧print(b)改为yield b就可以了 # 二、这就是定义generator的第二中方法。如果一个函数中包含yield关键字,那么这个函数就不是一个普通函数,而是一个generator def fib_generator(m): n, a, b = 0, 0, 1 while n < m: yield b a, b = b, a + b n = n + 1 return 'done' # 函数是顺序执行 遇到return语句或者最后一行函数语句就返回。而generator在每次调用next()的时候执行, 遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行 # 调用generator时 首先要生成一个generator对象 然后使用next()函数不断获得下一个返回值, ***同样的,函数改成的generator 基本不会使用next 去获取下一个返回值 而是使用for循环进行迭代 o = fib_generator(6) # print(next(o)) # 但是在使用for循环调用generator,发现拿不到generator的return语句的返回值,如果想要拿到返回值 必须捕捉StopIteration错误,返回值包括在StopIteration的value中 while True: try: x = next(o) print('value is:', x) except StopIteration as e: print('generator return value :', e.value) break # practice: 试用generator不断输出杨辉三角下一行的list # 1 # / \ # 1 1 # / \ / \ # 1 2 1 # / \ / \ / \ # 1 3 3 1 # / \ / \ / \ / \ # 1 4 6 4 1 # / \ / \ / \ / \ / \ # 1 5 10 10 5 1 def triangles(): N = [1] while True: yield N N.append(0) N = [N[i - 1] + N[i] for i in range(len(N))] n = 0 for t in triangles(): print(t) n = n + 1 if n == 10: break # 解析: # n = 2 # 时, N = [1, 0] # # range(len(N)) = [0, 1] # # 即:N = [N[i - 1] + N[i] for i in [0, 1]] # 即:N = [N[0 - 1] + N[0], N[1 - 1] + N[1]] # 即:N = [0 + 1, 1 + 0] = [1, 1] def triangles1(): a = [1] while True: yield a a = [sum(i) for i in zip([0] + a, a + [0])] n = 0 for t in triangles1(): print(t) n = n + 1 if n == 10: break # zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。 # 例如: a = [1, 2, 3] b = [4, 5, 6] # zip(a, b) == > [(1, 4), (2, 5), (3, 6)]