python复盘---每天一个小知识,生成器小记

196 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

复盘python,发现生成器一个有趣的东西

首先看现象

用生成器实现一个斐波那契数列

def fibonacci(times):
    n = 0
    a, b = 0, 1
    while n < times:
        # print(b)
        yield b
        a, b = b, a + b
        n += 1
    return


if __name__ == "__main__":

    g = fibonacci(5)
    print(type(g))    # 类型为generator
    print(type(fibonacci(5)))  # 类型为generator
    print(id(g))
    # for i in g:
    #     print(i)
    print(id(fibonacci(5)))  # 两者的内存地址也一样
    while True:
        try:
            x = next(g)   # 循环输出生成器的值,此种调用可输出所有的值
            print("value:%d" % x)
        except StopIteration as e:
            print("StopIteration")
        break

执行上述代码,运行结果如下:

value:1

value:1

value:2

value:3

value:5

StopIteration

如果把上述代码中的= next ( g ) 改为 x= next( fibonacci ( 5 ))

运行则会陷入死循环,只输出value:1

通过debug调试:

第一种方式执行到yield,第二次会接着执行yield后的代码

第二种方式每次都从函数开始执行到yield,yield后面不会执行

这是什么原因,两者都是生成器,内存地址也一样,按道理是一个生成器,运行结果为什么会不一样呢

运行结果不一样的原因

原因在于

(1)while 循环内

 next(fib(5)) 你这个next() 函数调用一次,函数中的 f(5) 是新的生成器调用,每次都是不同的生成器对象。

(2) while 循环前

 定义的 g=fibonacci(5) 然后在next(g)中的这个g是固定的一个生成器对象。**
 

id相同的原因

不过关于 id 相同的问题,Python 将内存划分为不同的区块,最小的单位为 block ,在生成对象时将会分配这个 block。在一个对象被销毁的时候,它的 block 被回收加入到 free-block 的顶端。如果紧接着新生成的对象和原对象大小一致的话,那么将直接从 free-block 取出我们刚刚放进去的 block。

因为 generator 对象不断销毁新建,每次新建时都使用上次 release 的 block