zoukankan      html  css  js  c++  java
  • 【Rollo的Python之路】Python 生成器

    Python 列表生成式:

    x从range里面取元素,然后对x进行运算,生成列表

    list1 = [x for x in range(10)]  #列表生成式
    
    print(list1)
    
    
    #执行结果:
    
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    或者可以这样:

    list1 = [x**2 for x in range(10)]  #列表生成式
    
    print(list1)
    
    #执行结果:
    
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

    运算符可以是函数:

    def f(x):
        return x**3
    
    list1 = [f(x) for x in range(10)]  #列表生成式
    
    print(list1)
    
    #执行结果:
    
    [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
    def f(x):
        return x**3
    
    list1 = [f(x) for x in range(10)]  #列表生成式
    
    print(list1)
    print(type(list1))
    
    #执行结果:
    
    [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
    <class 'list'>

    另一种赋值形式:要求一一对应,不然就报错。

    t = (123,"abc")
    
    a,b = t
    print(a)
    print(b)
    
    #执行结果:
    
    123
    abc
    t = [123,"abc",891]  #可以是列表
    
    a,b,c = t
    print(a)
    print(b)
    print(c)
    
    #执行结果:
    
    123
    abc
    891

    Python 生成器:一边循环,一边计算的机制,叫作生成器

    内存的效率

    生成器就是一个可迭代对象!!!

    生成器创建方式:

    1.0 小括号的方式(s = (x*2 for x in range(10)))

    2.0 yield创建

    s = (x*2 for x in range(10))
    print(s)
    
    #执行结果:
    
    <generator object <genexpr> at 0x0000000001EB6138>

    调用方法:next()

    s = (x*2 for x in range(10))
    
    print(next(s))
    print(next(s))
    print(next(s))
    print(next(s))
    
    #执行结果:
    
    0
    2
    4
    6

    相当于:__next__()

    s = (x*2 for x in range(10))
    
    print(s.__next__())
    print(s.__next__())
    print(s.__next__())
    print(s.__next__())
    
    #执行结果:
    
    0
    2
    4
    6

    超出了就会报错:StopIteration

    用for循环来遍历一次:

    s = (x*2 for x in range(10))
    
    for i in s:
        print(i)
    
    #执行结果:
    
    0
    2
    4
    6
    8
    10
    12
    14
    16
    18

     生成器函数:

    def generator_function():
        yield 
        

    在一个一般函数中使用yield关键字,可以实现一个最简单的生成器,此时这个函数变成一个生成器函数。yield与return返回相同的值,区别在于return返回后,函数状态终止,而yield会保存当前函数的执行状态,在返回后,函数又回到之前保存的状态继续执行。

    看看yield与return的区别:

    def generator_function1():
        print("ok")
        return 100 
    
    generator_function1()
    
    def generator_function():
        print("ok")
        yield 100
    generator_function()
    #执行结果: 
    ok
    def generator_function():
        print("ok")
        yield 100
    
    t = generator_function()
    print(t)
    
    #执行结果:
    <generator object generator_function at 0x00000000021F6138>

    所以yield函数就是一个生成器对象。

    def generator_function():
        print("ok")
        yield 100
        print("ok22")
        yield 99
    
    t = generator_function()
    print(t)
    
    next(t) #保留在yield 100
    next(t) #第二次从yied 100以下开始走。不是从开头走
    
    #执行结果:
    <generator object generator_function at 0x0000000002216138>
    ok
    ok22

     也可以用for:

    def generator_function():
        print("ok")
        yield 100
        print("ok22")
        yield 99
    
    for i in generator_function():
        print(i)
    
    
    #执行结果:
    
    ok
    100
    ok22
    99

    斐波那契数列

    def fibo(max):
        n,before,after = 0,0,1
       print(n) while n < max: print(after) before,after = after, before + after n = n + 1 fibo(10) #执行结果: 0 1 1 2 3 5 8 13 21 34 55

     用生成器来改:

    def fibo(max):
        n,before,after = 0,0,1
    
        while n < max:
            # print(after)
            yield before
            before,after = after, before + after
            n = n + 1
    
    g = fibo(8)
    print(g)
    
    print(next(g))
    
    #执行结果
    <generator object fibo at 0x0000000002216138>
    0

    yield()还有一个send()方法:

    send():可以传值,第一次进函数只能传None,等同于next(b)

    def battle():
        print("battle one")
        count = yield 1
        print(count)
    
        print("battle two")
        yield 2
        print("battle three")
        yield 3
    
    b = battle()
    b.send(None) #可以传值,第一次进函数只能传None,等同于next(b)
    b.send(99)

    for 循环语句,深入理解:

      1.0 for循环后面加的是可迭代对象。

          可迭代对象:内部有用iter()方法的对象都是可迭代对象。列表,元组,字典都是可迭代对象

      2.0 内部调用了next方法。

         

    生成器函数包含一个或者多个yield当调用生成器函数时,函数将返回一个对象,但是不会立刻向下执行像__iter__()和__next__()方法等是自动实现的,所以我们可以通过next()方法对对象进行迭代一旦函数被yield,函数会暂停,控制权返回调用者局部变量和它们的状态会被保存,直到下一次调用函数终止的时候,StopIteraion会被自动抛出生成器如何节省资源?

    只记住当前位置,生成器只保留一个值,next之后上一个值就没有了

    只有一个next方法

    生成器都是迭代器,迭代器不一定是生成器!!!

  • 相关阅读:
    【NOIP2007】守望者的逃离
    20200321(ABC)题解 by 马鸿儒 孙晨曦
    20200320(ABC)题解 by 王一帆
    20200319(ABC)题解 by 王一帆 梁延杰 丁智辰
    20200314(ABC)题解 by 董国梁 蒋丽君 章思航
    20200309(ABC)题解 by 梁延杰
    20200307(DEF)题解 by 孙晨曦
    20200306(ABC)题解 by 孙晨曦
    20200305(DEF)题解 by 孙晨曦
    20200303(ABC)题解 by 王锐,董国梁
  • 原文地址:https://www.cnblogs.com/rollost/p/10808209.html
Copyright © 2011-2022 走看看