对yield的理解,进行解析

# <======== 生成器概念 ========> 
详细介绍:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000

# 这种一边循环一边计算的机制,称为生成器: generator
# 可以被next()函数调用并不断返回下一个值的对象称为 迭代器: Iterator

# <======== 为何使用生成器? ========>
"""
    (1) 节省内存空间 : 只为了要前几个数据 没必要把所有的数据都遍历出来,一一放在像列表这样的集合类型数据中 它还得一个一个往内存里面装 如果有宇宙级别的数据量,还能都放下么?
    (2) 生成器可以算出下一个数据:按照某种算法推算出来,可以在循环的过程中不断推算出后续无限的数据元素,
        而你只需要往内存里存一个生成器   666
"""

# <======== 一.生成器定义 ========> 
L = [x * x for x in range(10)]    #相当于 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# print(L) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]  这个是列表推导式

# 第一种
g = (x for x in range(10))    #generator 
# print(g)  #<generator object <genexpr> at 0x7f4b6e9fbf10>  generator为生成器

"""
    # 总结1:定义一个生成器的基本形式是 (  推导式  ) 
      外边一个圆括号 里面是推导式   区别于 (1,2,3,4) 后者它是元祖~
    g = ( 1,2,3,4 )                  # 不是生成器
    g = [x * x for x in range(10)]   # 不是生成器
    g = ( x  for x in range(10) )    #   是生成器
"""

# 第二种 只要一个函数当中含有 yield 这样的关键字,此刻的函数odd不在是函数了 而叫做生成器 (先记住如下格式写法)
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield(5)
    
"""
    # 总结2: yield 有点像 return  意思 都是到这句话就停了 就把值返回了,
    # 但是yield不同在于 再次执行这个生成器时候会从上一次执行的位置继续向下走,它会记住上一次离开时的状态.
    # 每次返回退出 都会记住当前代码执行的位置,在继续执行的时候会从上一次的位置继续向下走
    yield 5 和 yield(5) 2种写法都可以 yield 5 更像 return 5 的写法
"""

# <======== 二.获取生成器中的元素 ========>
#   方法1 可以使用next(生成器) 可以得到生成器里面的下一个元素 
print(   next(g)  )  #0
print(   next(g)  )  #1
print(   next(g)  )  #2
print(   next(g)  )  #3
print(   next(g)  )  #4
"""
    .
    .
    .
    print(   next(g)  )
    如果超出了生成器的边界 如同超过了一个元祖的边界  会报错
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
"""

#   方法2 可以使用for 循环 因为这个生成器本身 也是可迭代对象 (即可循环对象) 不必担心越界问题
print("<==fengexian1==>")
g = (x * x for x in range(10))  # 从range(10) 取出一个作为x 然后x*x作为最后值拿出来
for n in g:
    print(n)


#   方法3 如果一个函数当中有yield这样的关键字,此刻的函数odd不在是函数了 而是生成器 
print("<==fengexian2==>")
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield 3
    print('step 3')
    yield 5   

# 想要获取元素:先实例化一个生成器对象  o是生成器对象 <generator object odd at 0x1022ef948>
o = odd()

扫描二维码关注公众号,回复: 2269409 查看本文章

# (1)可以使用next来获取 例如
print(next(o))    #step 1  1
print(next(o))    #step 2  3  
print(next(o))    #step 3  5
# print(next(o))    #越界 报错了...

# (2)避免越界尴尬 使用for循环
print("<==fengexian3==>")
p = odd()
for n in p:
    print(n)


    
    
    

# <======== 三.生成器基础案例 ========>  
# 他来表示一个无量无边的数据世界 应用在宇宙级别的数据量上 (如:恒河沙,阿僧祗,那由他)

print("<==fengexian4==>")
def shengchengqi(max):
    n=0
    while n < max:
        yield n
        n+=1

obj = shengchengqi(10)   #如果你写999999**999999 内存因太小会炸
for i in obj:
    print(i)


# 如果你想为这个生成器 在执行结束的时候 添加一个最终的返回值 
# 即return的效果 正常生成器是无法返回的 要依靠越界捕获异常 来实现

"""
    g = shengchengqi(10)
    while True:
        x = next(g)
        print('g:', x)
    Traceback (most recent call last):
      File "yield.py", line 110, in <module>
        x = next(g)
    StopIteration
    
    我们要的就是这个 StopIteration 异常 所以改写如下
"""
print("<==fengexian5==>")
def shengchengqi(max):
    n=0
    while n < max:
        yield n
        n+=1
    return "我出来了"
    
s = shengchengqi(10)
while True:
    try:
        x = next(s)
        print('g:', x)
    except StopIteration as e:
        # 这个 e.value 是来获取return 返回值的
        print('用e.value来获取return的返回值:', e.value)
        break
 

# ###########################################~经典算法~#############################################

# <======== 斐波那契数列 ========> 
"""
概念:
    除第一个和第二个数外,任意一个数都可由前两个数相加得到:
    如:1, 1, 2, 3, 5, 8, 13, 21, 34 ... ...
"""

def fib(max):
    n, a, b = 0, 0, 1  # 即n=0 用于while计数 a记录上一次的变量值 b作为下一次要打印的数字 开始分别初始化为0和1
    t = 0
    while n < max:
        yield b
        a , b = b , a+b  #先把b赋值给a  再把a+b赋值给b 好处就是相加时候用的是a与b的初始化值 而不是经过交换后的ab值 即展开代码如下
        """
            t = a
            a = b
            b = b+t
        """
        n = n + 1

obj = fib(6)
# print(next(obj))
for i in obj:
    print(i)


    
# <======== 杨辉三角 ========> 
"""
概念:
              1
             / \
            1   1
           / \ / \
          1   2   1
         / \ / \ / \
        1   3   3   1
       / \ / \ / \ / \
      1   4   6   4   1
     / \ / \ / \ / \ / \
    1   5   10  10  5   1

    把每一行看做一个list,试写一个 generator ,不断输出下一行的list:
"""
print("<==fengexian1==>")
def yanghuisanjiao(max):
    L = [1]
    i=0
    while i<max:
       yield L
       L =  [1] +[  L[i]+L[i+1] for i in range( len(L)-1 ) ] + [1]
       i+=1

obj = yanghuisanjiao(5)
for j in obj:
    print(j)

"""
    L = [1]+[]+[2]
    print(L) #[1,2]

解析:
    [1,1]
    L[0] + L[1] = 1+1 = 2   #0
    [1]+[2]+[1] = [1,2,1]
    .
    [1,2,1]
    L[0] + L[1] = 1+2 = 3   #0
    L[1] + L[2] = 2+1 = 3   #1
    [1]+[3]+[3]+[1] = [1,3,3,1]
    .
    [1,3,3,1]
    L[0] + L[1] = 1+3 = 4   #0
    L[1] + L[2] = 3+3 = 6   #1
    L[2] + L[3] = 3+1 = 4   #2
    [1] + [4] + [6] + [4] + [1] = [1,4,6,4,1]
    .
    .
    .
"""


# <======== 背下来 大概率面试题 ========> 

# 协程
"""
    Python对协程的支持是通过generator实现的。
    传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
    如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:
"""

猜你喜欢

转载自blog.csdn.net/ren_ger/article/details/81088903
今日推荐