• python笔记十(列表生成式、字典生成式、生成器、生成器的并行)


    一、列表生成式

      列表生成式就是python设置的可以用来可以生成列表的

      如要生成一个0-9的列表我们可以通过以下代码实现:

    >>> list(range(10))
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

      但是如果生成的列表较为复杂呢?例如生成包含0²、1²、2²。。。9²这样一个列表;

    >>> L = []
    >>> for i in range(10):
    ...     L.append(i*i)
    ...
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

      在上述代码中,我们通过for循环将数值append到列表L中,虽然可以实现,但是也是low爆了~~~,以下通过一行代码搞定!!!

    >>> [i*i for i in range(10)]
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

      除此之外,列表生成式还可以生成更为复杂的列表。通过列表生成式可以快速生成格式化的列表、字典

    复制代码
    >>> d ={"name":"nadech","age":"22","address":"NANJING"}
    >>> [key+"="+value for key,value in d.items()]
    ['name=nadech', 'age=22', 'address=NANJING']


    >>> from numpy.random import randn
    >>> data ={i:randn() for i in range(7)}
    >>> data
    {0: 0.05824826050892203, 1: 0.08046687699730207, 2: 1.860740808203487, 3: 1.577136929714018, 4: -0.5473223742129686, 5: 0.13849329354272613, 6: 1.4133333866268165}



    复制代码

    二、生成器

      通过列表生成式,我们可以直接创建一个列表的所有元素。

      但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

      如果列表可以按照需求,一边循环一边计算,就可以解决上述问题。这种机制就叫做生成器(generator)。

      生成器共有两种形式,第一种就是把列表生成式中的[ ]改为( );第二种就是含有yield

    复制代码
    >>> g = (i*i for i in range(1,3))
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration

     >>> (i*i for i in range(10))
     <generator object <genexpr> at 0x0000029EA41490F8>

     >>> for i in g:
     ... print(i)
     ...
     1
     4

     
    复制代码

      上述代码加粗部分可以看出,创建生成器返回的是一个生成器对象的地址,并不是直接包含所有的元素的列表。

      通过调用next,可以生成下个元素的值,不过在实际使用中我们并不会通过多次调用next,而是通过for循环来获取生成器的元素。

      第二种我们要介绍的就是包含yield的,首先我们先实现打印输出这样一串数字,除了第一个数,后一个数都等于前两个数字的和 1,1,2,3,5,8....这就是著名的斐波那契数列,不要被这名字吓到,总之就是实现输出上边的一串数字。

    复制代码
    >>> def fib(max):
    ...     n, a, b = 0, 0, 1
    ...     while n < max:
    ...         print(b)
    ...         a, b = b, a + b
    ...         n = n + 1
    ...     return 'done'
    ...
    >>> fib(5)
    1
    1
    2
    3
    5
    'done'
    复制代码

      接下来,我们对上述代码进行一处修改,把print改为yield

    复制代码
    >>> def fib(max):
    ...     n,a,b = 0,0,1
    ...     while n<max:
    ...             yield(b)
    ...             a,b = b,a+b
    ...             n=n+1
    ...     return "done"
    ...
    >>> fib(5)
    <generator object fib at 0x000001F8B9C2AF68>

     >>> o = fib(6)
     >>> for i in o:
     ... print (i)
     ...
     1
     1
     2
     3
     5
     8

    复制代码

      可见,命令窗口返回一个generator对象的内存地址。通过迭代输出生成器 o中的数字。

      但是,细心的朋友可能发现,我们通过for循环来输出生成器的内容的时候,并没有输出return的“done”,这样我们就需要通过next来依次输出,同时就伴随另外一个问题的产生,当next输出到最后的时候,会抛出一个StopIteration的异常,我们需要将次异常捕获。(异常的捕获后边会详细介绍)

    复制代码
    >>> while True:
    ...     try:
    ...         x = next(o)
    ...         print("o:",x)
    ...     except StopIteration as e:
    ...         print("RETURN VALUE:", e.value)
    ...         break
    ...
    o: 1
    o: 1
    o: 2
    o: 3
    o: 5
    o: 8
    RETURN VALUE: done
    复制代码

      

    三、生成器的并行

      搞清楚了生成器的特点,那么我们简单的利用生成器来实现一个并行的效果,实际上这是一个假的并行。

      这个生成器并行的例子,叫做大猪和小猪吃包子。

    复制代码
    import time
    def consumer(name):
        print("%s 准备好吃包子了" % name)
        while True:
            type = yield     #此处的yield,可以接受producer中send的传值
            print("%s包子被%s 吃了" % (type, name))
    
    
    def producer(name):
        print("%s 已经准备好做包子了~~~~"%name)
        c = consumer("大猪") #这时候不是正常的函数调用了,只是生成一个生成器队形,不执行函数体内容,调用next会执行
        c1 = consumer("小猪")
    
        next(c)
        next(c1)
    
        items = ["白菜","菠菜","生菜"]
        for item in items :
            time.sleep(1)
            print("%s已经做好了两个包子"%name)
            c.send(item)
            c1.send(item)
    
    
    producer("nadech")
    复制代码
  • 相关阅读:
    如何优化代码和RAM大小
    Ubuntu14.04用apt在线/离线安装CDH5.1.2[Apache Hadoop 2.3.0]-old
    PHP和Golang使用Thrift1和Thrift2访问Hbase0.96.2(ubuntu12.04)
    Flume+Kafka+Strom基于伪分布式环境的结合使用
    Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用
    mac10.9+php5.5.15+brew0.9.5的安装
    kafka2.9.2的伪分布式集群安装和demo(java api)测试
    Flume1.5.0的安装、部署、简单应用(含伪分布式、与hadoop2.2.0、hbase0.96的案例)
    ubuntu12.04+proftpd1.3.4a的系统用户+虚拟用户权限应用实践
    ubuntu12.04+kafka2.9.2+zookeeper3.4.5的伪分布式集群安装和demo(java api)测试
  • 原文地址:https://www.cnblogs.com/jjchi/p/9723895.html
Copyright © 2020-2023  润新知