这里面主要还是一些基础的知识,之前自己在印象笔记里面也有相应的整理的过程,总之相互结合,最后的目的是能够对知识点的掌握。

生成器:generator

  1. 单纯通过列表生成式有时会很占相应的内存空间
  2. 列表元素按照某种算法推算出来,可以在循环的过程中不断的推算出后续的元素,可以不用创建完整的list,可以节省大量的存储空间
  3. 一边循环一边计算的机制:generator
  4. 创建一个generator的方法:
    • 把列表生成式的[]改为()
    • 如果要打印出generator的每一个元素:通过next()函数获得返回值
    • 改进每次都需要不断的next的操作,采用for循环来迭代(generator也是可以迭代的对象),不需要关心产生的StopIteration的错误
    • 第二种方法:如果函数定义中包含了yield关键字,函数不再是普通函数,是generator函数,调用一个generator函数就会返回一个generator
  5. 工作原理:
    • 在for循环的过程中不断的计算出下一个元素,并在适当的条件结束for循环
    • 对于函数改成的generator来说,遇到return或执行到函数体最后一行语句就是结束generator指令,for循环结束
    • 普通函数调用直接返回结果,generator函数的调用返回一个generator对象
  6. 案例:斐波拉契数列

几个小例子辅助理解:

# 采用for循环来迭代,不需要关心产生的StopIteration的错误
g = (x * x for x in range(10))
for n in g:
    print(n)
# 打印结果如下
0
1
4
9
16
25
36
49
64
81
# 当推算的算法比较的复杂的时候,用列表生成式的for循环无法实现的时候,用函数实现比较好
# 用斐波拉契数列来说明
def fib(max):
    n,a,b=0,0,1
    while n<max:
        print(b)
        a,b=b,a+b
        n=n+1
    return "done"
print(fib(6))
# 打印结果
1
1
2
3
5
8
done

由上面的演算逻辑可知:fib函数定义了斐波拉契数列的推算规则,可以从第一个元素开,推算处后续的任意元素。这种逻辑类似与generator,将上面的代码中的print(b)改为yield b,就可以把fib函数变成generator函数

# 由于包含关键字,函数不再是一个普通函数,调用一个generator函数将会返回一个generator
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
print(fib(6))
# 运行结果
<generator object fib at 0x000002CFDD443C80>

附加理解:generator函数与普通函数的执行流程不同:

  1. 普通函数:顺序执行,遇到return或者是最后一行函数语句就返回
  2. 对于generator函数来说:每次调用next()的时候执行,遇到yield语句返回,再次执行时的时候返回yield语句处处继续执行
# 因此将上面的代码进行改进,不用next()来获取下一个返回值,直接用for循环迭代
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
for n in fib(6):
    print(n)
# 打印结果如下:
# 没有获取return语句的返回值
1
1
2
3
5
8

想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
    
g=fib(6)
while True:
    try:
        x=next(g)
        print('g:',x)
    # 为了捕获StopIteration错误
    except StopIteration as e:
        print('Generator return value:' ,e.value)
        break
# 打印结果如下:
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

迭代器:Iterable

for循环的数据类型的以下几种:

  1. 合数据类型:list 、tuple、dict、set、str等
  2. generator:包含生成器和带yield的generator function
    • 可以直接作用于for循环的对象的为可迭代对象:Iterable
    • 可以使用isinstance()判断一个对象是否是Iterable对象
    • 不但可以作用于for循环,还可以被next()函数不断的调用并返回下一个值,直到抛出StopIteration错误无法继续返回下一个值
    • 生成器都是Iterator对象,但list、dict、str虽然都是Iterable,不是Iterator
    • 把list、dict、str等Iterable变成Iterator可以使用iter()函数:
  3. 总结:
    • 凡是可以作用于for循环的对象的都是Iterable类型
    • 凡是可作用于 next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
    • Python的for循环本质上就是通过不断调用next()函数实现的
ToTOP