生成器13

生成器
    # 凡是函数体内存在yield关键字,调用函数体不会执行函数体代码,会得到一个返回值,该返回值就是生成器对象
    # 需要提示的是,生成器是一个特殊的迭代器
#     next的功能就是为了触发函数体的执行
#     yield可以让函数暂停在本次循环的位置,当再有next调用触发时,就会继续本次调用的位置继续往下执行,如此循环往复。
# 实例:生成器对象
# def func():
#     print('first')
#     yield 1#1是自己定义的yied返回值
# g=func()
# print(g)
# 输出结果:
# <generator object func at 0x004CE2A0>
            # 实例:生成器对象调用
            # def func():
            #     print('first')
            #     yield 1#1是自己定义的yield返回值
            #     print('second')
            #     yield 2
            #     print('third')
            #     yield 3
            # g=func()    #这里是一行代码都没有运行,如果想要触发生成器,就需要调用next的方法,g呢是一个函数,
            #             # 也将会触发g函数体内的代码执行,
            # res1=next(g)#会触发函数的执行,直到碰到一个yield停下来,并且将yield后的值当作本次next的结果返回
            #             # 迭代器调用next会返回一个值,可以将值赋值给一个变量res,res只是第一次迭代返回的值
            #             # 过程:
            #                 #1.next防止调用
            #                 #2.g函数体内代码执行,遇到第一个yield停止,并返回结果
            # res2=next(g)#第二次# 迭代,返回res2

# 自定义一个跟内置的range函数一样的生成器
# def my_range(start,stop,step):
#     while start < stop:
#         yield start
#         start +=step

        # 取值方式1,使用迭代器,next触发函数运行,一个个的取出,要多少取多少,不会浪费内存空间,
                    # 再大的数字也不会担心内存溢出,但是for循环取值的话,是一次性取出范围内所有的值,如果超过容器最大的范围
                    # 会造成内存溢出
        # g=my_range(1,10,1)
        # res1=next(g)
        # print(res1)
        # res2=next(g)
        # print(res2)
        # res3=next(g)
        # print(res3)
        # res4=next(g)
        # print(res4)

        # 取值方式2,使用for循环
        # for i in my_range(1,100000000,1):
        #     print(i)

                #列表,每个元素都存在列表里
                # g1=[x*x for x in range(10)]
                # print(g1)

        #生成器,是一个可以产生出列表元素的算法工具,在使用时,才能产生需要的列表元素。
        # 使用方式:
        #     1.直接使用next()进行调用,因为生成器本身就是一个迭代器,拥有__iter__和__next__内置方法
        #     2.可以使用for循环把生成器内的元素遍历出来,for循环使用的就是__iter__和__next__同样的机制
                # g2 = (x*x for x in range(10))
                # print(g2)

                #输出对比
                # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
                # <generator object <genexpr> at 0x010EE2D0>

                # 案例1
                #斐波那契数列:
                # def fib1(max):
                #      n,a,b=0,0,1
                #      while n < max:
                #          print(b)
                #          a,b=b,a+b
                #          n = n + 1
                #      return 'done'#函数的返回值,给出函数执行的最后的结果,可以不写,但是最好带上,以免产生不必要的麻烦
                # fib1(10)#调用函数,执行函数体内的代码
                # print(fib1.__name__)#函数名字
                # print(fib1)#函数的内存地址

                #改写成生成器的方式:
                # def fib2(max):
                #     n,a,b=0,0,1
                #     while n<max:
                #         yield b
                #         a,b=b,a+b
                #         n = n + 1
                #     return 'done'
                #f=fib2(10)#接收fib的生成器的返回值,yied的返回值定义的是b,下次next操作时是接着本次循环往后接续取值。
                # #第一次取值
                # res1=next(f)
                # print(res1)
                # #第二次取值
                # res2=next(f)
                # print(res2)
                # for i in fib2(6):
                #     print(i)
                # 案例2
                # def odd():
                #     print('step 1')
                #     yield 1    #第一次取值时,遇到yied中断,返回值为1
                #     print('step 2')
                #     yield(3)    #第二次取值时,继续第一次中断的地方继续往下执行,
                #                 # 遇到第二个yied时中断,完成了第二次的取值,返回值3,依次进行
                #     print('step 3')
                #     yield(5)
                # o=odd()
                # next(o) #第一次
                # next(o) #第二次
                # next(o) #第三次
                # next(o)#第四次取值时因为超出了范围就报错

                # yied表达式形式的应用
                #             x=yield #yied 的表达式形式
                #             .send()#给yied传值
                # 实例
                # 针对yied表达式的使用,
                #                 第一步:
#                                         现使用next将函数停在yied的位置,
#                                         或者使用‘,send(None)’传一个none得值给yied,如果第一次没有传空值,就会有如下报错
                                                # def func(name):
                                                #     print("%s往前跳"%name)
                                                #     while True:
                                                #         num=yield
                                                #         print("%s往前跳了%s步"%(name,num))
                                                #
                                                # f=func('joke')

                                                # 输出结果
                                                # f.send(2)
#                                                 f.send(2)
#                                             TypeError: can't send non-None value to a just-started generator

                #                 第二步:使用‘.send’给yied传值
                #                 第三步:使用next就可以使停在yied的位置的函数进行往下运行,while循环再次停在yied的位置
                #                         然后再‘.send’给yied传值,往复循环,就会源源不断的有值进去。
                #                     注:‘,send’本身就有next的功能,当传完值后,无需使用next,即可继续往下走
                            # def func(name):
                            #     print("%s往前跳"%name)
                            #     while True:
                            #         num=yield
                            #         print("%s往前跳了%s步"%(name,num))
                            #
                            # f=func('joke')
                            # next(f)
                            # f.send(1) #第一次传值,必须传空值none(next之后无需再传空值)
                            # f.send(2)
                            # f.send(4)


# 总结:
#     1.yied只能在函数内使用
#     2.yied提供了一种自定义迭代器的解决方案
#     3.yied可以保存函数的暂停状态
#     4.yied与return
#                   相同之处都可以返回值,值得类型和个数都没有限制
#                   不同之处,yied可以返回多次值,return只能返回一次值


# 生成器表达式
#     l=[1,2,3,4]#列表生成式
#     l=(1,2,3,4)#生成器表达式,把[]换成()即可
#

            # 实例
            # 注:生成器对象在没有进行next调用时是没有进行yield执行的,即不使用不触发;不next不执行
            #生成器内部不存值,值是内部在每次调用时制造出来。
            #
            # g=(i**2 for i in range(1,5) if i>3)
            # print(next(g))#停在第一次满足i>3后获得的i值处,i=4
            # print(next(g))#第二次进行yied操作,满足条件,停在i=5的地方
            # print(next(g))#第三次进行next操作的时候,已超过了范围内,就会报错,停止执行

            #注:为了不导致内存溢出,使用生成器
            # 实例:
            # 统计文件内的字符数
            # 方式1
            # with open('今日内容','rt',encoding='utf-8') as f:
            #     data=f.read()
            #     print(len(data))
            # 问题:所有文本的内容全部读取到内存,如果文件过大,将会导致内存不够使用,进而导致内存溢出
            # 方式2
            # with open('今日内容','rt',encoding='utf-8') as f:
            #     res=0
            #     for line in f:
            #         res +=len(line)
            #     print(res)
            # 问题:是没导致内存溢出,因为是一行一行的进行读取的,但是使用了for自己定义的循环,繁琐了很多
            # 方式:3
            #
            # with open('今日内容','rt',encoding='utf-8') as f:
            #     print(sum(len(line) for line in f))
                # 生成器表达式:(len(line) for line in f)  #生成器对象
                # 再使用sum内置函数求和sum()

            # 面试关于生成器实例:
            # def add(n,i):
            #     return n+i
            #
            # def test():
            #     for i in range(4):
            #         yield i
            #
            # g=test()
            # for n in [1,10]: #n=10
            #     g=(add(n,i) for i in g)


            # 分析:

                # 第一次循环:
            #      n=1,没有触发生成器对象的函数体代码,整个的函数的代码,将原封不动的传给g
                # g=(add(n,i) for i in test())
                #                         test中i=0,1,2,3
                #                         n+i=10,11,12,13
                #                         g=(10,11,12,13)

                # 第二次循环:
            #      n=10时 next,触发了函数体里的代码
                # g=(add(n, i) for i in (add(n,i) for i in test()))
                #                             (add(n,i) for i in test())=(10,11,12,13)
                #                             n+i=20,21,22,23
                #                             g=(20,21,22,23)

            # print(n)
            # res=list(g)

            # 迭代器1=(add(n,i) for i in test())
            # for i in 迭代器1: #i=next(迭代器1) i=11
            #     add(n, i) #add(10,11)


            #A. res=[10,11,12,13]
            #B. res=[11,12,13,14]
            #C. res=[20,21,22,23]
            #D. res=[21,22,23,24]
            # 答案:c


# 内置函数
# 常用的内置函数,了解熟悉,用到时查看下具体的用法
# abs、max、sum、min、等等

# 面向过程编程
#         是一种机械式的思维方式,一步步的解决问题,以一种流程的方式编写
#         优点:复杂的问题流程化,简单化
#         缺点:可扩展性差

 

posted on 2018-12-26 20:30 漫天飞雪世情难却 阅读( ...) 评论( ...)   编辑 收藏

转载于:https://www.cnblogs.com/jokezl/articles/10181584.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值