乱入:生成器+习题复习

##:生成器
            (虽然说生成器和迭代器可以说是Python近几年来引入的最强大的两个概念,但是生成器的学习并不涉及到高级的魔法方法,甚至巧妙的避开了类和对象,仅需要通过普通的函数就可以实现了,由于生成器的概念比较高级,所以在之前的函数章节并没有讲到它,学习就是需要一个渐进的过程。像上一节课的迭代器,很多人学了之后就感觉很简单,但是如果我们把迭代器放到循环那一章节来讲,大家势必就会一头雾水了。)

            (生成器事实上是迭代器的一种实现,那既然迭代器可以实现,那为什么还要生成器呢?有一句老话说得好:“存在即合理”。生成器的发明一方面就是使得Python更为简洁,因为迭代器需要我们去定义一个类和实现相关的方法,才可以定义一个灵活的迭代器。而生成器需要在普通的函数加上一个 yield 语句。另外一个重要的方面就是生成器的发明使得Python模仿协同程序的概念得以实现。)

            (所谓的协同程序就是可以运行的独立函数的调用,函数可以暂停或者挂起,并且在需要的时候从函数上一次离开的地方继续或者重新开始。那我们知道,对于一个普通的函数来说,我们调用它一般都是从函数的第一句开始走,结束用 return 语句或者 异常 或者 函数所有的语句执行完毕。一旦函数将控制权交还给调用者,那就意味着全部都结束了,因为我们说过:函数的所有的工作、保存都是局部变量,局部变量在调用结束都会自动消失。)

            (而生成器就是一个特殊的函数,调用可以中断、可以暂停,暂停之后他把控制权临时交出来,然后交完之后,在需要的时候他又能够获取回来,重新获得控制权,从上一次暂停的时候继续下去。这就是生成器(Generator)。)
在这里插入图片描述
            (如上面的例子,一旦一个函数里面出现 yield 语句,那么这个函数就被定义为生成器,yield 相当于函数里面的 return 语句,但是普通函数的 return 一返回,这个函数就结束了,但是对于生成器来说,出现 yield,它就会把 yield 后面的参数给返回,然后就暂停在这个 yield 的位置,下一次执行就从这里开始。如程序执行所示,第一次 next() 时,就打印了 1,第二次 next() 就继续打印了 2,如果没有数据了继续 next() 就抛出了 StopIteration 的异常。Python的 for 循环会自动调用 next() 方法和探测 StopIteration 结束,如下:)
在这里插入图片描述
            (上节课斐波那契数列的例子,也可以用生成器来实现:)
在这里插入图片描述
            (在列表里加一个 for 语句就是列表推导式,下面的就是求100以内能被2整除,但是不能被3整除的整数。)
在这里插入图片描述
            (Python3 除了有列表推导式之外,还有字典推导式:)
在这里插入图片描述
            (还有集合推导式:)
在这里插入图片描述
            (照这种情形想下去,很多人就会以为会有字符串推导式和元组推导式,下面试一下:)
在这里插入图片描述
            (由上面可以看出,只要出现双引号,它就会把里面的内容如实打印出来,因为这就是字符串。下面试试元组推导式)
在这里插入图片描述
            (可以看到,打印的不是元组(tuple),这里没有打印数据,但是出现了 generator (生成器),没错,这里我们的铺垫有点长,这里用普通的圆括号括起来的,就是生成器推导式。下面是证明:)

在这里插入图片描述            (上面所示就是生成器推导式,其实,还有一点特性更牛,生成器推导式如果作为函数的参数他可以直接写推导式就可以了,不用圆括号,如下)
在这里插入图片描述
            关于生成器的技术要点,详情请看拓展阅读 解释 yield 和 Generators(生成器)

##温故知新之习题
            0. 通常,一般的函数从第一行代码开始执行,并在什么情况下结束?
           答:对于调用一个普通的 Python 函数,一般是从函数的第一行代码开始执行,结束于 return 语句、异常或者函数所有语句执行完毕。一旦函数将控制权交还给调用者,就意味着全部结束。函数中做的所有工作以及保存在局部变量中的数据都将丢失。如果再次调用这个函数时,一切都将重新开始。

           1. 什么是协同程序?
           答:所谓的协同程序就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。

           Python 是通过生成器来实现类似于协同程序的概念:生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。

            2. 生成器所能实现的任何操作都可以由迭代器来代替吗,为什么?
           答:是的,都可以。因为生成器事实上就是基于迭代器来实现的,生成器只需要一个 yield 语句即可,但它内部会自动创建 __iter__() 和 __next__() 方法。

            3. 将一个函数改造为生成器,说白了就是把什么语句改为 yield 语句?
           答:return 语句。

            4. 说到底,生成器的最大作用是什么?
           答:使得函数可以“保留现场”,当下一次执行该函数是从上一次结束的地方开始,而不是重头再来。

            5. 如下,get_prime() 是一个获得素数的生成器,请问第 2 行代码 while True 有何作用?

def get_primes(number):
    while True:
        if is_prime(number):
            yield number
        number += 1

           答:这个 while True 循环是用来确保生成器函数永远也不会执行到函数末尾的。只要调用 next() 这个生成器就会生成一个值。这是一个处理无穷序列的常见方法(这类生成器也是很常见的)。

##动动手
            要求实现一个功能与 reversed() 相同(内置函数 reversed(seq) 是返回一个迭代器,是序列 seq 的逆序显示)的生成器。例如:

>>> for i in myRev("FishC"):
    print(i, end='')
 
ChsiF

           答:

def myRev(data):
    # 这里用 range 生成 data 的倒序索引
    # 注意,range 的结束位置是不包含的
    for index in range(len(data)-1, -1, -1):
        yield data[index]

            1. 10 以内的素数之和是:2 + 3 + 5 + 7 = 17,那么请编写程序,计算 2000000 以内的素数之和?

           答:如果你的策略是将 2000000 以内的所有素数找到并存放到一个列表中,再依次进行求和计算,那么这个列表极有可能会撑爆你的内存。所以这道题就必须用到生成器来实现啦。

           详细解释请参考: 解释 yield 和 Generators(生成器)

           结果是 142913828922,你答对了吗?!

import math
 
def is_prime(number):
    if number > 1:
        if number == 2:
            return True
        if number % 2 == 0:
            return False
        for current in range(3, int(math.sqrt(number) + 1), 2):
            if number % current == 0:
                return False
        return True
    return False
 
def get_primes(number):
    while True:
        if is_prime(number):
            yield number
        number += 1
 
def solve():
    total = 2
    for next_prime in get_primes(3):
        if next_prime < 2000000:
            total += next_prime
        else:
            print(total)
            return
 
if __name__ == '__main__':
    solve()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值