一番码客 : 挖掘你关心的亮点。
http://www.efonmark.com
本文目录:
[TOC]
先看几个例子。
例子一:生成一个1~10的整数列表
1 | list = [1,2,3,4,5,6,7,8,9,10] |
或者,
1 | list = range(1,11) |
例子二:生成一个1~10的每个整数的平方数的列表
1 | list = [] |
2 | for num in range(1, 11): |
3 | list.append(num*num) |
虽然确实是实现了预期的需求,但是需要通过多行代码才能实现,过程非常繁琐,一点都不pythonic。
为了实现类似需求,python提供了一些高级特性来简化,就是列表推导式。
列表推导式
列表推导式(List Comprehensions)是python内置的非常简单且强大的可以用来轻松创建列表(List)的方法。
例子三:用列表推导式创建1~10的所有整数的平方数的列表
1 | for num in range(1,11)] list = [num*num |
2 | list |
3 | [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] |
可见,列表推导式的书写规则是,生成的元素放在语句前面,紧跟着的是for循环。
而且,在列表推导式的循环后面加上条件判断 。
列子四:创建1~10的所有偶数平方数的列表
1 | for num in range(1,11) if num%2 == 0] list = [num * num |
2 | list |
3 | [4, 16, 36, 64, 100] |
例子五:使用两个for循环将两个列表中的元素进行全排列,继而生成新的列表
1 | for char in ['a', 'b', 'c'] for num in ['1','2', '3']] list = [char+num |
2 | list |
3 | ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3'] |
生成器表达式
基于列表继续扩展,如果列表元素的个数持续扩大,达到10万个,如此大的列表将占据巨大的内存。假设程序实际上只需要访问列表中其中的几个元素,那么列表占用的绝大多数内存空间都是多余的,纯属浪费。Python为了解决这个问题,引入生成器(generator)。
可以通过生成器表达式将列表改为一个生成器。 列表一旦被创建,其包含的元素就实实在在地存在内存中,占据着内存空间,列表存放的是元素本身,而生成器存放的是算法,通过next()
调用算法实时生成元素,因此生成器占用的内存空间很小。
将列表推导式的方括号[]改为小括号()即可创建一个生成器。
例子六:
1 | for num in range(1,6)) g = (num * num |
2 | g |
3 | <generator object <genexpr> at 0x0000018E0754F228> |
4 | next(g) |
5 | 1 |
6 | next(g) |
7 | 4 |
8 | next(g) |
9 | 9 |
10 | next(g) |
11 | 16 |
12 | next(g) |
13 | 25 |
14 | next(g) |
15 | Traceback (most recent call last): |
16 | File "<stdin>", line 1, in <module> |
17 | StopIteration |
说明:可以看到,列表list一旦被创建,内存中就存放所有元素,而生成器g的元素内容将随着next()函数的调用实时生成,直到最后没有元素可生成时,抛出StopIteration错误。
生成函数器
除了表达式可以变为生成器之外,函数同样可以变为生成器。
例子七:编写一个函数,通过该函数可以计算出任意自然数的平方数。
1 | #!usr/bin/env python |
2 | def square(input): |
3 | list = [] |
4 | for num in range(input): |
5 | list.append(num * num) |
6 | print(list) |
7 | return list |
8 | |
9 | for num in square(5): |
10 | print(num) |
结果:
1 | [0] |
2 | [0, 1] |
3 | [0, 1, 4] |
4 | [0, 1, 4, 9] |
5 | [0, 1, 4, 9, 16] |
6 | 0 |
7 | 1 |
8 | 4 |
9 | 9 |
10 | 16 |
说明:可以看到square()
函数在运行过程中会创建一个列表,假设想要计算的自然数变大,那么列表也会变大,此程序便会占据大量的内存,当自然数无限大时,程序将因无法分配到足够的内存而崩溃。
例子八:借助生成器,将square()
函数改为生成器函数。
1 | #!usr/bin/env python |
2 | def square(input): |
3 | for num in range(input): |
4 | print('before yield') |
5 | yield num * num |
6 | print('after yield') |
7 | |
8 | for num in square(5): |
9 | print(num) |
结果:
1 | before yield |
2 | 0 |
3 | after yield |
4 | before yield |
5 | 1 |
6 | after yield |
7 | before yield |
8 | 4 |
9 | after yield |
10 | before yield |
11 | 9 |
12 | after yield |
13 | before yield |
14 | 16 |
15 | after yield |
说明:
- 可以看到,使用生成器函数同样实现了与普通函数同样的功能。
- 它们有如下区别:生成器代码更简洁。 对比两者的代码,除了用于打印提示信息的代码之外,生成器的代码量更少,结构更为简洁。生成器内存占用极少。生成器并没有创建列表,更不会因为自然数的变大而消耗大量的内存; 普通函数则面临严重的内存问题。运行方式不同。 普通函数是顺序执行的,直到执行完最后一行语句或者遇到return语句就返回;而生成器函数则是遇到
yield
语句返回,再次执行时,从上次离开的地方继续执行。
参考: - 《物联网Python开发实战》 |
![]() |
免费知识星球:一番码客-积累交流 微信公众号:一番码客 微信:Efon-fighting 网站:http://www.efonmark.com |