Python 基础 - Day 4 Learning Note - Generator 生成器

列表生成器/列表解析 list comprehension

  • 简单灵活地创建列表,通常和lambda(), map(), filter() 一起使用
  • 通过列表生成式, 直接创建列表。但是,收到内容限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问几个元素,那其他的就白占空间。列表生成器能够一边循环一边计算,大大节省大量的空间。是生成器的一种。 

  • 只有调用,才能生成。 不支持切片操作,只能通过__next()___一个个取数字。

基本语法

[expr for iter_var in iterable]
or
[expr for iter_var in iterable if cond_expr]

案例

# example 1:
>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# example 2: 迭代3行5列的矩阵
q = [(x+1, y+1) for x in range(3) for y in range(5)]
print(q)
list comp

 

生成器

定义

生成器是列表生成器的一个扩展。 在python中,这种一边循环一边计算的机制,称为生成器 generator; 每次计算一个条目后,把这个条目“生成“(yield)出来, 这个过程成为”延迟计算“ (lazy evaluation),所以在使用内存上更有效。在语法上,生成器就是一个带yield语句的函数。

生成器的特征:

  1. 只有调用才生成。 否则算法不占内存
  2. 生成器的调用,只能够记住当前位置。 可以同 generator.__next__() 方法来调用下一个对象,但是无法回到过去的位置。 可以for循环打印
  3. 不支持切片等列表操作,只能一个一个取

yield函数使函数变生成器,是构建生成器的方法。 生成器的好处在于能够中途停下,附加其他功能,然后再继续调用。 

应用:

1. 调用函数中的一个值并跳出函数,下次进入继续调用下个值。以下面斐波拉契Fibonacci数列为例:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b  # 知识点1 - yield的功能,返回一个值给调用者并暂停执行。
        a, b = b, a + b   # 重新赋值的过程, 左边的a,b是新生的, 右边的过去的值运算
        n = n + 1
    return "done"    # return 的作用是next调用时可能出现异常处理的返回值。

print(fib(10))  # 返回变为一个generator: <generator object fib at 0x0000026FAA8A78E0>

# 知识点2 - 调用元素的方式
f = fib(10)
for i in f:
    print(i)  # 用for循环,函数返回值done不会打印

# 知识点3 - next()调用出现异常的情况
g = fib(6)
while True:
    try:
        x = next(g)     # 内置方法,= __next__一样。 当达到一个真正的返回或者函数结束没有更多的值返回,一个StopIteration异常将会抛出。所以需要处理异常,通过try ... expect... 语句
        print('g:',x)
    except StopIteration as e:
        print('Generator return value: ', e.value)   # e.value 返回的是 done

2. 协同程序。协同程序是可以运行的独立函数调用,可以暂停或者挂起,并从程序离开的地方继续或者重新开始。在有调用者和(被调用者)协同程序也有通信。举例来说,当协同程序暂停的时候,我们能从其中获得一个中间的返回值,当调用回到程序中时,能够传入额外或者改变了的参数,但仍能够从我们上次离开的地方继续,并且所有状态完整。生成器的作用是挂起返回出中间值并多次继续的协同程序。

 1 #!usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # 通过yield实现在单线程的情况下实现并发运算的效果,或者; 典型的生产者 - 消费者模型.这是以后异步IO的雏形。
 4 
 5 import time
 6 
 7 
 8 def consumer(name):
 9     print('%s 准备吃包子啦' %name)
10     while True:
11         baozi = yield   # yield
12         print('包子[%s]来了,被[%s]吃了' %(baozi,name))
13 
14 
15 def producer(name):
16     c = consumer('A')   # 将函数变成生成器
17     c2 = consumer('B')
18     c.__next__()        # 第一次调用生成器
19     c2.__next__()
20     print('老子开始准备吃包子啦!')
21     for i in range(10):
22         time.sleep(1)
23         print("做了2个包子!")
24         c.send(i)   # send的作用是唤醒并给yield传值,next只是调用yield
25         c2.send(i)
26 
27 producer("alex")
最简单的协程 - 吃包子例子

 

Reference

1. Python之路,Day4 - Python基础4 (new版),http://www.cnblogs.com/alex3714/articles/5765046.html

2. 《Python 核心编程 V2》page 205 - 207; page 305 - 307

 

转载于:https://www.cnblogs.com/lg100lg100/p/7282547.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值