zoukankan      html  css  js  c++  java
  • 自学Python4.8-生成器(方式二:生成器表达式)

    自学Python之路-Python基础+模块+面向对象
    自学Python之路-Python网络编程
    自学Python之路-Python并发编程+数据库+前端
    自学Python之路-django

    自学Python4.8 - 生成器(方式二:生成器表达式)

     

    定义:生成器(generator)是一个包含yield关键字的函数,当它被调用的时候,在函数体中的代码不会被执行,而是会返回一个迭代器。
              (一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);      
                  如果函数中包含yield语法,那这个函数就会变成生成器;)

    • 生成器是一个特殊的程序,可以被用作控制循环的迭代行为
    • 生成器类似于返回值为数组的一个函数,这个函数可以接收参数,可以被调用,但是,不同于一般的函数会一次性返回包含了所有数值的数组,生成器一次 只产生一个值,这样消耗的内粗数量大大减少,而且允许调用函数可以很快的开始处理前几个返回值。因此,生成器看起来像一个函数但是表现的却像一个迭代器

    python提供了两种基本的生成器方式:

    • 生成器函数:也是用def来定义,利用关键字yield一次返回一个结果,阻塞,重新开始
                           每次请求一个值,就会执行生成器中的代码,知道遇到一个yield或者return语句
                           ①yield语句意味着应该生成一个值
                           ②return语句意味着要停止执行(不生成任何东西,只有在一个生成器中使用时才能进行无参数调用)
    • 生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果

    2.  生成器表达式: 

     生成器表达式来自于迭代和列表解析的组合,生成器表达式和列表解析类似,但是他使用尖括号而不是方括号括起来的。

    print([ x ** 3 for x in range(5)]) # 列表推导式
    print((x ** 3 for x in range(5))) # 生成器表达式
    print(list(x ** 3 for x in range(5)))# 两者之间转换
    

    输出:

    for n in (x ** 3 for x in range(5)):
        print('%s, %s' % (n, n * n))  # 就操作而言,生成器表如果使用大量的next()函数会显得十分不方便,for循环会自动出发next函数  

    输出:

    [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理

    [满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] #筛选功能

    举例1:
    30以内所有能被3整除的数
     
    举例2:
    30以内所有能被3整除的数的平方
    举例3:
    找到嵌套列表中名字含有两个‘e’的所有名字
    names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
    ret = [name for lst in names for name in lst if name.count('e') ==2]
    print(ret)

    字典推导式

    举例1:

    将一个字典的key和value对调

    举例2:

    合并大小写对应的value值,将k统一成小写

     

    举例3:

    集合推导式,自带结果去重功能

     

    3. 生成器函数与协程生成器表达式比较

      一个迭代既可以被写成生成器函数,也可以被协程生成器表达式,均支持自动和手动迭代。而且这些生成器只支持一个active迭代,也就是说生成器的迭代器就是生成器本身。

    def recv():
        print('Are your ready:')
        while True:
            n = yield  #yield语句还有更给力的功能,作为一个语句出现在赋值运算符的右边,接受一个值,或同时生成一个值并接受一个值
            print('总共用了 %s 秒' % n)
    c = recv()
    c.__next__()
    c.send(100)
    c.send(300)
    

    输出:

    解释:以上这种方式使用yield语句的函数称为协程。在这个例子中,对于__next__的初始调用是必不可少的,这样协程才能执行可通向第一个yield表 达式的语句。在这里协程会挂起,等待相关生成器对象send()方法给它发送一个值。传递给send()的值由协程中的yield表达式返回。 协程的运行一般是无限期的,使用方法close()可以显式的关闭它。

    def split_line():
        print('ready to split')
        result = None
        while True:
            line = yield result  #如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值
            result = line.split()
    s = split_line()
    s.__next__()
    print(s.send('1,2,3'))
    

    输出:

    解释:

    这个例子中的先后顺序非常重要。首个next()方法让协程执行到yield result,这将返回result的值None。
    在接下来的send()调用中,接收到的值被放到line中并拆分到result中。
    send()方法 的返回值就是下一条yield语句的值。也就是说,send()方法可以将一个值传递给yield表达式,但是其返回值来自下一个yield表达式,而不是接收send()传递的值的yield表达式。

    ③  如果想用send()方法来开启协程的执行,必须先send一个None值,因为这时候是没有yield语句来接受值的,否则就会抛出异常

    def split_line():
        print('ready to split')
        result = None
        while True:
            line = yield result  #如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值
            result = line.split()
    s=split_line()
    print(s.send('1 2 3'))

    输出:

    def split_line():
        print('ready to split')
        result = None
        while True:
            line = yield result  #如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值
            result = line.split()
    s=split_line()
    print(s.send(None))
    print(s.send('1 2 3'))

    输出:

    ④ 生成器的功能非常强大。协程可以用于实现某种形式的并发。在某些类型的应用程序中,可以用一个任务调度器和一些生成器或协程实现协作式用户空 间多线程,即greenlet。

    yield的威力将在协程,协同式多任务处理(cooperative multitasking),以及异步IO中得到真正的体现。

    ...

  • 相关阅读:
    [转].net mvc + vuejs 的项目结构
    Outlook IMAP 修改PST文件存储路径
    VS2017 性能优化方法
    查询存储过程所需参数
    如何保障微服务架构下的数据一致性
    sqlserver批量给用户配置存储过程权限
    vue中刷新当前页面或重新加载的两种方法
    vue history模式下的微信支付,及微信支付授权目录的填写,处理URL未注册
    Vue 四行代码实现无感知上拉加载更多
    2019年前端必用正则(js)
  • 原文地址:https://www.cnblogs.com/yaoyaojcy/p/10591674.html
Copyright © 2011-2022 走看看