Python中的列表生成式与生成器

1. 列表生成式

列表生成式是 Python 内置的非常简单却强大的可以用来创建list的生成式, 一次性生成所有数据,然后保存在内存中,适合小量数据。我们通过以下实例来说明。

1.例如要实现将1-100所有偶数的平方返回,用生成式方法,如下:

li = [x*x for x in range(1,21) if x%2 == 0] # if后面的条件语句用来筛选出偶数
print(li) # 打印出此列表生成式

# 结果
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

2.运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:

import os # 导入os模块
li = [d for d in os.listdir('.')] # os.listdir 可以列出文件和目录

# 结果
['.idea', 'design.py', 'drawn.py', 'guess_num.py', 'my_requests.py', 'my_urlopen.py', 'test.py', 'venv']

3.列表生成式也可以使用两个变量来生成list:

dict = {'x': 'A', 'y': 'B', 'z': 'C' } # 创建一个字典
li = [k + '=' + v for k, v in dict.items()] # 用 items() 函数以列表返回可遍历的(键,值)元组
print(li)

# 结果
['y=B', 'x=A', 'z=C']

2. 生成器(generator)

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在 Python 中,这种一边循环一边计算的机制,称为生成器(Generator)。

要创建一个 generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个 generator:

g = (x * x for x in range(10))
print(g)

# 结果
 at 0x000000000223C518>

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过generator的__next__()方法:

print(g.__next__()) # 0
print(g.__next__()) # 1
print(g.__next__()) # 4
print(g.__next__()) # 9
print(g.__next__()) # 16
print(g.__next__()) # 25
print(g.__next__()) # 36
print(g.__next__()) # 49
print(g.__next__()) # 64
print(g.__next__()) # 81
print(g.__next__()) 
# Traceback (most recent call last):
  File "D:/workspace/spider/test1/test.py", line 28, in 
    print(g.__next__())
StopIteration

generator 保存的是算法,每次调用__next__(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的错误。

上面这种不断调用next()方法稍显复杂,正确的方法是使用for循环,因为 generator 也是可迭代对象:

for n in g:
    print(n)

# 结果
0
1
4
9
16
25
36
49
64
81

3. 总结

  1. 当表达式的结果数量较少的时候, 使用列表生成式还好,快速生成,比较节省时间, 如果数量级过大, 那么列表生成式就会占用很大的内存。
  2. 生成器并不是立即把结果写入内存, 而是保存的一种计算方式, 通过不断的获取, 可以获取到相应的位置的值,所以占用的内存仅仅是对计算对象的保存,比较节省内存,但稍显耗费时间。

你可能感兴趣的:(Python中的列表生成式与生成器)