高级特性
列表生成式¶
当要生成list
时, 可以用list(range(1,11))
, 但如果生成[1x1, 2x2,..., 10x10]
, 一般用循环
1 | L=[] |
可以用一行语句替换循环生成上面的list [x * x for x in range(1, 11)]
同时, for
循环后面还可以加上if
判断 [x * x for x in range(1, 11) if x % 2 == 0]
还可以循环嵌套
for…if/if…else…for…的区别¶
- 在使用列表生成式时, 如果在
for...
后使用if...
来限定, 则不加else
语句, 因为这个if
是一个筛选条件 - 如果在列表生成式中, 先用
if...
, 则必须加else...
, 因为这表示一个条件语句, 不论前面的表达式是否需要迭代
生成器¶
通过列表生成式, 我们可以直接创建一个列表; 但受到内存限制, 列表容量有限, 而且我们可能只访问前面的几个元素, 那后面绝大多数的元素白白浪费
在这种情况下, 我们可以用生成器
generator
, 在循环的过程中不断推算出后续元素, 而不必创建完整的列表
生成方法¶
-
将一个列表生成式的
[]
改成()
, 将创建了一个generator
1
2
3for i in range(10)) L = (x * x
L
<generator object <genexpr> at 0x1022ef630> -
在一个函数中包含
yield
关键字如: 斐波那契数列的实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# 普通函数
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n += 1
return 'done'
# 生成器
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n += 1
return 'done'
使用方法¶
- 可以通过
next()
函数获得生成器的下一个返回值(注: 因为生成器保存的是算法, 所以每次调用next()
就计算出下一个值, 直到计算到最后一个元素后, 再使用就抛出StopIteration
错误) - 使用
for
循环, 因为生成器也是可迭代对象, 同时此时也不要关心StopIteration
错误
理解难点¶
将一般的列表生成式变为生成器的执行流程较好理解, 但将函数变为生成器后的执行流程理解比较困难
函数是顺序执行, 遇到return
语句或最后一行函数语句返回, 而变成生成器后, 函数在每次调用next()
时执行, 遇到yield
返回, 再次执行时从上回返回的yield
语句处继续执行, 直到遇到return
语句或函数体的最后一条语句
在使用for
循环迭代生成器时, 无法获得return
的返回值; 如果想拿到, 必须捕获StopIteration
错误, 返回值包含在StopItreation
的value
中
迭代器¶
可以直接作用于for
循环的数据类型有以下几种:
- 集合数据类型, 如:
list
,tuple
,dict
,set
,str
等 generator
, 包括生成器和带yield
的generator function
定义¶
这些可以直接作用于for
循环的对象统称为可迭代对象Iterable
, 可使用isinstance()
判断
而generator
不仅可以作用于for
循环, 还可以被next()
不断调用并返回下一个值, 而可以被next()
调用并不断返回下一个值的对象称为迭代器Iterator
也即, **可迭代对象Iterable
包括迭代器Iterator
及不属于迭代器的list
, dict
, str
等可迭代对象; 而迭代器Iterator
包括生成器generator
**及由iter()
函数转化后的list
, dict
, str
等
原因¶
Iterator
对象表示一个数据流, 其可以被next()
函数调用并不断返回下一个数据, 直到没有数据抛出StopIteration
错误; 可以把这个数据流看作一个有序序列, 但我们却不能提前知道序列的长度, 所以Iterator
的计算是惰性的, 只有在需要返回下一个数据时它才会计算, 因此它可以表示一个无限大的数据流, 如: 全体自然数
for循环的实质¶
1 | for x in [1, 2, 3, 4, 5]: |