列表生成式
列表生成式是 python 内置的非常强大的可以用来生成列表的生成式。在学习生成器之前先来了解一下列表生成式,者有利于我们队生成器的理解。
列表生成式的语法格式如下
[exp for iter_var in iterable if_exp]
列表生成式的实际执行过程如下:
- 迭代 iterable 中的每个元素,每次迭代都先判断 if_exp 表达式结果为真,如果为真则进行下一步,如果为假则进行下一次迭代;
- 把迭代结果赋值给 iter_var,然后通过 exp 得到一个新的计算值;
- 最后把所有通过 exp 得到的计算值以一个新列表的形式返回。
如果迭代得到的元素无需过滤的话,if_exp 可以省略。
我们如果要生成一个 1 至 100 的整数的列表可以使用 list(range(1,101)), 如果要 1 到 100 的整数的平方我们可以使用循环来实现
list = [] for x in range(1, 101): list.append(x * x) print(list)
除了使用选好我们还可以使用列表生成式来实现
list = [x * x for x in range(1, 101)] print(list)
现在我们需要 1 至 100 中所有偶数的的平方,我们也可以使用列表生成式来实现
list = [x * x for x in range(1, 101) if x % 2 == 0] print(list)
通过使用列表生成式我们可以写出简洁的代码来快速的初始化列表。
生成器
生成器从名字上来看可以理解为生成数据的工具。生成器按照某种特定的规则不断的生成数据,直到结束为止。
生成器的语法规则如下:
(exp for iter_var in iterable if_exp)
从形式上看生成器和列表生成式非常相似,生成器仅仅是将列表生成式的方括号换成了圆括号。而实际使用上却有很大的差别,列表生成式一次生成一个列表若列表的元素过多则占用很大的内存空间,而生成器一次仅生成一个元素即节省了内存空间又可以获取完整的列表内容。
#!/usr/bin/env python3 # -*- coding:utf-8 -*- list1 = [x * x for x in range(1, 20) if x % 2 == 0] list2 = (x * x for x in range(1, 20) if x % 2 == 0) print(type(list1)) print(type(list2)) print(list1) print(list2) for n in list2: print(n) for n in list2: print(n)
以上代码执行结果如下:
<class 'list'> <class 'generator'> [4, 16, 36, 64, 100, 144, 196, 256, 324] <generator object <genexpr> at 0x101163390> 4 16 36 64 100 144 196 256 324
从以上代码的执行结果我们可以看出,使用列表生成式即生成了一个完整的列表,包含了列表的所有元素;使用生成器产生的是一个生成器,本身未含有任何元素,当我们使用 for 循环进行迭代时可以获取生成器生成的整个列表的元素,但是生成器仅能迭代一次,迭代完成后将无法再获取内容,这也是迭代器的特性。
生成器解具有很多用途,在很多地方替代列表使用是一个不错的选择。特别是针对大量值的时候,列表占内存较多,生成器的优势就在于少占内存,因此无需将生成器实例化为一个列表,直接对其进行操作,方显示出其迭代的优势。
以上列表是比较简单的生成器,可以直接使用列表生成式修改得到,如果是比较复杂的生成器则需要使用包含 yield 的函数来实现。下面我们通过 yield 函数来实现上面的列表(包含 1 至 20 中所有偶数的平方)。
#!/usr/bin/env python3 # -*- coding:utf-8 -*- def even_squares(start, end): for n in range(start, end): if n % 2 == 0: yield n * n list = even_squares(1, 20) print(type(list)) print(list) for n in list: print(n)
以上代码执行结果如下
<class 'generator'> <generator object even_squares at 0x10aa38c00> 4 16 36 64 100 144 196 256 324
从以上代码运行结果可以看出使用 yield 函数和使用列表生成式的生成器获取的结果完全相同。
生成器具有以下特点:
- 可以使用类似列表生成式的方式生成,也可以使用 yield 函数生成。
- 生成器只在使用时才生成数据,可用来节省内存空间。
- 生成器实际是一个特殊的迭代器,可以使用 for 循环进行迭代。
- 只记录当前的位置,只能向前不能向后,「生成器只能使用一次,再次使用需重新初始化」。