列表生成式

当要生成list时, 可以用list(range(1,11)), 但如果生成[1x1, 2x2,..., 10x10], 一般用循环

1
2
3
4
5
L=[]
for x in range(1, 11):
L.append(x * x)

print(L) # [1, 4, 9, 16,..., 100]

可以用一行语句替换循环生成上面的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…的区别

  1. 在使用列表生成式时, 如果在for...后使用if...来限定, 则不加else语句, 因为这个if是一个筛选条件
  2. 如果在列表生成式中, 先用if..., 则必须加else..., 因为这表示一个条件语句, 不论前面的表达式是否需要迭代

生成器

通过列表生成式, 我们可以直接创建一个列表; 但受到内存限制, 列表容量有限, 而且我们可能只访问前面的几个元素, 那后面绝大多数的元素白白浪费

在这种情况下, 我们可以用生成器generator, 在循环的过程中不断推算出后续元素, 而不必创建完整的列表

生成方法

  1. 将一个列表生成式的[]改成(), 将创建了一个generator

    1
    2
    3
    >>> L = (x * x for i in range(10))
    >>> L
    <generator object <genexpr> at 0x1022ef630>
  2. 在一个函数中包含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'

使用方法

  1. 可以通过next()函数获得生成器的下一个返回值(: 因为生成器保存的是算法, 所以每次调用next()就计算出下一个值, 直到计算到最后一个元素后, 再使用就抛出StopIteration错误)
  2. 使用for循环, 因为生成器也是可迭代对象, 同时此时也不要关心StopIteration错误

理解难点

将一般的列表生成式变为生成器的执行流程较好理解, 但将函数变为生成器后的执行流程理解比较困难

函数是顺序执行, 遇到return语句或最后一行函数语句返回, 而变成生成器后, 函数在每次调用next()时执行, 遇到yield返回, 再次执行时从上回返回的yield语句处继续执行, 直到遇到return语句或函数体的最后一条语句

在使用for循环迭代生成器时, 无法获得return的返回值; 如果想拿到, 必须捕获StopIteration错误, 返回值包含在StopItreationvalue

迭代器

可以直接作用于for循环的数据类型有以下几种:

  1. 集合数据类型, 如: list, tuple, dict, set, str
  2. generator, 包括生成器和带yieldgenerator 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
2
3
4
5
6
7
8
9
10
for x in [1, 2, 3, 4, 5]:
pass

# 上式完全等价于下式
it = iter([1, 2, 3, 4, 5])
while True:
try:
x = next(it)
except StopIteration:
b