列表生成器/列表解析 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)
生成器
定义
生成器是列表生成器的一个扩展。 在python中,这种一边循环一边计算的机制,称为生成器 generator; 每次计算一个条目后,把这个条目“生成“(yield)出来, 这个过程成为”延迟计算“ (lazy evaluation),所以在使用内存上更有效。在语法上,生成器就是一个带yield语句的函数。
生成器的特征:
- 只有调用才生成。 否则算法不占内存
- 生成器的调用,只能够记住当前位置。 可以同 generator.__next__() 方法来调用下一个对象,但是无法回到过去的位置。 可以for循环打印
- 不支持切片等列表操作,只能一个一个取
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