- 列表解析式的语法:[返回值 for 元素 in 可迭代对象 if 条件]
- 使用中括号[],内部是for循环
- if条件语句可选
- 返回一个新的列表
列表解析式是一种语法糖,编译器会优化,不会因为简写而影响效率,反而因优化提高了效率。减少程序员工作量,减少出错。简化了代码,但可读性增强。
- 比如要生成一个列表,元素0~9,对每一个元素自增1后求平方返回新列表,下面看不用列表解析式和用列表解析式的代码。
>>> lst = []
>>> for i in range(10):
i = (i+1)**2
lst.append(i)
>>> lst
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> lst = [(i+1)**2 for i in range(10)]
>>> lst
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
- 打印20以内的偶数
>>> lst = []
>>> for i in range(20):
if i%2 == 0:
lst.append(i)
>>> print(lst)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
>>> lst = [i for i in range(20) if i%2==0]
>>> print(lst)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
有这样的赋值语句newlist = [print(i) for i in range(10)],请问newlist的元素打印出来是什么?
newlist = [print(i) for i in range(10)]
print(newlist)
结果为:
0
1
2
3
4
5
6
7
8
9
[None, None, None, None, None, None, None, None, None, None]
比如获取20以内同时被2、3整除,下面的代码是不行的。
>>> lst = [i for i in range(20) if i%2==0 elif 1%3==0]
SyntaxError: invalid syntax
and可以
>>> lst = [i for i in range(20) if i%2==0 and i%3==0]
>>> lst
[0, 6, 12, 18]
[expr for item in iterable if cond1 if cond2]
这等价于:
ret = []
for item in iterable:
if cond1:
if cond2:
ret.append(expr)
获取20以内同时被2、3整除
>>> lst = [i for i in range(20) if i%2==0 if i%3==0]
>>> lst
[0, 6, 12, 18]
[expr for i in iterable1 for j in iterable2 ]
等价于:
ret = []
for i in iterable1:
for j in iterable2:
ret.append(expr)
相当于嵌套for循环。
- 列表里的元素为字典
>>> lst = [{i:j} for i in range(5) for j in 'abc']
>>> lst
[{0: 'a'}, {0: 'b'}, {0: 'c'}, {1: 'a'}, {1: 'b'}, {1: 'c'}, {2: 'a'}, {2: 'b'}, {2: 'c'}, {3: 'a'}, {3: 'b'}, {3: 'c'}, {4: 'a'}, {4: 'b'}, {4: 'c'}]
- 列表的元素为集合
>>> lst = [{i,j} for i in range(5) for j in 'abc']
>>> lst
[{0, 'a'}, {0, 'b'}, {0, 'c'}, {1, 'a'}, {1, 'b'}, {1, 'c'}, {2, 'a'}, {2, 'b'}, {'c', 2}, {3, 'a'}, {'b', 3}, {'c', 3}, {4, 'a'}, {'b', 4}, {'c', 4}]
>>> lst = [{1,0} for i in range(5) for j in 'abc']
>>> lst #不存在set去重的考虑
[{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}]
>>> id(lst[0])
3024216889608
>>> id(lst[1])
3024216887592
- 复杂结构
>>> lst = [(i,j) for i in range(6) for j in range(20,25) if i >=3 if i**2 >j]
>>> lst
[(5, 20), (5, 21), (5, 22), (5, 23), (5, 24)]
有一个列表lst = [1,4,9,16,2,5,10,15],生成一个新列表,要求新列表元素是lst相邻2项的和
lst = [1,4,9,16,2,5,10,15]
result = []
for i in range(len(lst)-1):
result.append(lst[i]+lst[i+1])
print(result)
[5, 13, 25, 18, 7, 15, 25]
#下面用列表解析式
lst = [1,4,9,16,2,5,10,15]
result = [lst[i]+lst[i+1] for i in range(len(lst)-1)]
print(result)
[5, 13, 25, 18, 7, 15, 25]
打印九九乘法表
先看下普通写法
for i in range(1,10):
for j in range(1,i+1):
print("{}*{}={:>2}".format(j,i,j*i),end= '\n' if j == i else ' ')
用列表解析式
lst = [print("{}*{}={:>2}".format(j,i,j*i),end= '\n' if j == i else ' ') for i in range(10) for j in range(2,i+1)]
- 生成器的语法为:(返回值 for 元素 in 可迭代对象 if 条件)
- 它就是将列表解析式的中括号换成小括号就行了
- 它返回的是一个可迭代的生成器对象
>>> (x for i in range(5))
<generator object <genexpr> at 0x000002C0216572C8>
- 生成器表达式是按需计算(或称惰性求值、延迟计算),需要的时候才计算
- 列表解析式是立即返回值
- 生成器是Python中一个特殊的程序,用于控制循环的迭代行为。相对于一般函数用return来一次性返回所有值,生成器使用yield关键字,一次只返回一个值。
- 是一个可迭代对象
- 是一个迭代器
这样的设计有很大的好处:在数据处理时,如果函数return出来的是一个非常大的数组,那么会非常占用内存,有时会报MemoryError的错误,而使用yield后一次仅仅返回一个元素值,可以优化内存占用的情况
利用生成器表达式生成生成器
>>> lst = [1,4,9,16,2,5,10,15]
>>> result = (lst[i]+lst[i+1] for i in range(len(lst)-1)) #生成器表达式为我们生成一个生成器对象出来
>>> type(result)
<class 'generator'>
利用生成器
>>> a = (i*2 for i in range(5))
>>> type(a)
<class 'generator'>
>>> next(a)
0
>>> next(a)
2
>>> for i in a:
print(i)
4
6
8
>>> next(a)
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module> #走到尽头
next(a)
StopIteration
>>> for i in a:
print(i)
#输出为空
>>>
>>> it = ( print("{}".format(i+1)) for i in range(2))
>>> first = next(it)
1
>>> second = next(it)
2
>>> val = first + second
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
val = first + second
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
>>> first
>>> second
>>> None+None
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
None+None
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
生成器表达式延迟计算,列表解析式立即计算
- 单从返回值本身来说,生成器表达式节省内存,列表解析式返回新的列表
- 生成器没有数据,内存占用极少,它是使用的时候一个个返回数据,如果将这些返回的数据合起来占用的内存和列表解析式也差不多,但是它不需要占用这么多内存
- 列表解析式构造新的列表需要立即占用内存,不管你是否立即使用这么多数据
- 单看计算时间看,生成器表达式耗时非常短,列表解析式时间长
- 但是生成器本身并没有返回任何值,只返回了一个生成器对象
- 列表解析式构造并返回了一个新的列表,所有看起来耗时了
- {返回值 for 元素 in 可迭代对象 if 条件}
- 列表解析式的中括号换成大括号就行
- 立即返回一个集合
- {(x,x+1) for x in range(10)}
- {[x] for x in range(10)} #错误的,集合里的元素为可哈希,列表不可哈希
>>> {(x,x+1) for x in range(5)}
{(0, 1), (1, 2), (4, 5), (2, 3), (3, 4)}
- {x:(x+1) for x in range(5)}
{0: 1, 1: 2, 2: 3, 3: 4, 4: 5}
- {x:[x,x+1] for x in range(5)}
{0: [0, 1], 1: [1, 2], 2: [2, 3], 3: [3, 4], 4: [4, 5]}
- {(x,):[x,x+1] for x in range(5)}
{(0,): [0, 1], (1,): [1, 2], (2,): [2, 3], (3,): [3, 4], (4,): [4, 5]}
- {chr(0x41+x):x**2 for i in range(10)}
{'C': 4}
- {str(x):y for x in range(5) for y in range(4)}
{str(x):y for x in range(5) for y in range(4)}