list comprehension,列表解析:
语法:
[返回值 for 元素 in 可迭代对象 if 条件]
注:
列表解析没有elif,如果有多个条件可用多个if或配合or或and使用;
列表解析是语法糖:
编译器会优化,不会因为简写而影响效率,反而因优化提高了效率,不仅字节码更少,而且减少了栈针;
减少程序员工作量,减少出错;
简化了代码,可读性增强;
例:
生成一个列表,元素0-9,对每一个元素自增1后求平方,返回新列表;
[(i+1)**2 for i in range(0,10)]
例:
获取10以内的偶数,比较执行效率;
方一:
[i for i in range(0,10) if i % 2 == 0]
方二:
even = []
for i in range(10):
if not i % 2: #常用not这种写法,同if i % 2 == 0:
even.append(i)
print(even)
例:
[0 for _ in range(10)]
[[0] for _ in range(10)]
习题:
1、有这样的赋值语句:newlist=[print(i) for i in range(10)],newlist的元素打印出的是什么?
In [3]: newlist=[print(i) for i in range(5)]
0
1
2
3
4
In [4]: newlist
Out[4]: [None, None, None, None, None] #print(i)是表达式的结果或函数计算的结果,print(i)输出到屏幕了,该列表解析没有返回值,即最后生成指定个数的None
2、获取20以内的偶数?如果是3的倍数也打印?
In [6]: [i for i in range(20) if not i%2]
Out[6]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
In [7]: [i for i in range(20) if not i%2 or not i%3] #list comprehension没有elif,多个条件用多个if或配合or,and使用
Out[7]: [0, 2, 3, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18]
3、获取20以内既能被2整除又能被3整除的数?
方一:
In [7]: [i for i in range(20) if not i%2 and not i%3]
Out[7]: [0, 6, 12, 18]
方二:
In [8]: [i for i in range(20) if not i%2 if not i%3]
Out[8]: [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)
[expr for i in iterable1 for j in iterable2]
等价于
ret=[]
for i in iterable1:
for j in iterable2:
ret.append(expr)
例:
In [10]: [(i,j) for i in 'abc' for j in range(3)]
Out[10]:
[('a', 0),
('a', 1),
('a', 2),
('b', 0),
('b', 1),
('b', 2),
('c', 0),
('c', 1),
('c', 2)]
In [11]: [[i,j] for i in 'abc' for j in range(3)]
Out[11]:
[['a', 0],
['a', 1],
['a', 2],
['b', 0],
['b', 1],
['b', 2],
['c', 0],
['c', 1],
['c', 2]]
In [12]: [{i:j} for i in 'abc' for j in range(3)]
Out[12]:
[{'a': 0},
{'a': 1},
{'a': 2},
{'b': 0},
{'b': 1},
{'b': 2},
{'c': 0},
{'c': 1},
{'c': 2}]
习题:
(1)如下语句的输出?
In [17]: [(i,j) for i in range(7) for j in range(20,25) if i>4 if j>23]
Out[17]: [(5, 24), (6, 24)]
In [18]: [(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
Out[18]: [(5, 24), (6, 24)]
In [19]: [(i,j) for i in range(7) for j in range(20,25) if i>4 and j>23] #常用此种
Out[19]: [(5, 24), (6, 24)]
(2)返回1到10平方的列表?
In [20]: [i**2 for i in range(1,11)]
Out[20]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
(3)lst=[1,4,9,16,2,5,10,15],生成一个新列表,要求新列表元素是lst相邻两项之和?
lst = [1,4,9,16,2,5,10,15]
[lst[i]+lst[i+1] for i in range(len(lst)-1)]
(4)打印九九乘法表?
[print('{}*{}={:<3}{}'.format(j,i,i*j,'\n' if i==j else ''),end='') for i in range(1,10) for j in range(1,i+1)]
(5)'0001.abadicddus'是ID格式,要求ID格式以点号分割,左边是4位从1开始的整数,右边是10位随机小写英文字母,请依次生成前100个ID的列表?
方一:
import random
['{:04}.{}'.format(i,''.join([chr(random.randint(97,122)) for _ in range(10)])) for i in range(1,101)]
方二:
import random
import string
['{:04}.{}'.format(i,''.join([random.choice(string.ascii_lowercase) for _ in range(10)])) for i in range(1,101)]
方三:
import random
['{:04}.{}'.format(i,''.join([random.choice(bytes(range(97,123)).decode()) for _ in range(10)])) for i in range(1,101)]
注:
ascii,american standard code for information interchange,美国信息交换标准代码;
小写a-z对应ascii码的97-122;
ascii码表的0-127常用,0-9,\t,\n,\r,space对应的ascii;
chr(),将ascii码对应的数字转为字符;
0-31,127,33个控制字符,或通信专用字符;
32-126,95个字符;
32,空格;
48-57,0-9数字;
65-90,26个大写英文字母;
97-122,26个小写英文字母;
8,退格;
9,制表;
10,换行;
13,回车;
generator expression,生成器表达式:
语法:
(返回值 for 元素 in 可迭代对象 if 条件)
列表解析的[]换为()即可;
返回一个生成器;
和list comprehension区别:
generator expression是按需计算,或称惰性求值(延迟计算,python思想),需要的时候才计算值,不需要的时候给个对象(可理解为中间状态,是一种可迭代对象);
list comprehension是立即返回值;
预计算和延迟计算,都有应用场景;
生成器:
iterable,可迭代对象;
iterator,迭代器;
iterable不一定是iterator,iterator一定是iterable;
next(),用next()方法测试是否是iterator;
在迭代时最好用for控制,如果直接用next()要控制好边界,否则抛异常;
迭代完后,不能回头;
生成器总结:
延迟计算;
返回迭代器,可以迭代;
从前到后走完一遍后,不能回头;
列表解析总结:
立即计算;
返回的不是迭代器,返回可迭代对象列表;
从前到后走完一遍后,可重新回头迭代;
例:
In [1]: [i for i in range(5)]
Out[1]: [0, 1, 2, 3, 4]
In [2]: (i for i in range(5))
Out[2]: <generator object <genexpr> at 0x7fc6440cc9e8>
In [3]: for x in (i for i in range(5)):
...: print(x)
...:
0
1
2
3
4
In [11]: g=('{:04}'.format(i) for i in range(1,4))
In [12]: next(g)
Out[12]: '0001'
In [13]: next(g)
Out[13]: '0002'
In [14]: next(g)
Out[14]: '0003'
In [15]: next(g)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-15-e734f8aca5ac> in <module>()
----> 1 next(g)
StopIteration:
In [16]: g=('{:04}'.format(i) for i in range(1,4)) #iterator最好用for控制
In [17]: for i in g:
...: print(i)
...:
0001
0002
0003
In [23]: lc=['{:04}'.format(i) for i in range(5)]
In [25]: for x in lc:
...: print(x)
...: print('############')
...: for x in lc:
...: print(x)
...:
0000
0001
0002
0003
0004
############
0000
0001
0002
0003
0004
习题:
it=(print('{}'.format(i+1)) for i in range(2))
first=next(it)
second=next(it)
val=first+second
val的值是什么? #报错,print()语句是输出到控制台,该生成器返回值为None
val=first+second语句之后,能否再次next(it)? #不能
In [18]: it=(print('{}'.format(i+1)) for i in range(2))
In [19]: type(it)
Out[19]: generator
In [20]: first=next(it)
1
In [21]: second=next(it)
2
In [22]: val=first+second
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-663c3b91df51> in <module>()
----> 1 val=first+second
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
生成器表达式和列表解析式的对比:
计算方式,生成器表达式延迟计算,列表解析式立即计算;
内存占用,单从返回值本身来说,生成器表达式省内存,列表解析式返回新的列表(构造出新的列表,需占用内存);生成器没有数据,内存占用极少,但使用时,虽然一个个返回数据,但合起来占用的内存也差不多;
计算速度,单从计算时间看,生成器表达式耗时非常短,列表解析式耗时时间长;但是生成器本身并没有返回任何值,只返回了一个生成器对象;列表解析式构造并返回了一个新的列表;
集合解析式:
语法:
{返回值 for 元素 in 可迭代对象 if 条件}
{}
立即返回一个集合;
例:
In [26]: {(x,x+1) for x in range(5)}
Out[26]: {(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)}
In [27]: {[x] for x in range(5)}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-27-a39ffa943c7e> in <module>()
----> 1 {[x] for x in range(5)}
<ipython-input-27-a39ffa943c7e> in <setcomp>(.0)
----> 1 {[x] for x in range(5)}
TypeError: unhashable type: 'list'
字典解析式:
语法:
{返回值 for 元素 in 可迭代对象 if 条件}
{},用key:value形式;
立即返回一个字典;
例:
In [28]: {x:(x,x+1) for x in range(5)}
Out[28]: {0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5)}
In [29]: {x:[x,x+1] for x in range(5)}
Out[29]: {0: [0, 1], 1: [1, 2], 2: [2, 3], 3: [3, 4], 4: [4, 5]}
In [30]: {[x]:[x,x+1] for x in range(5)}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-32f94dcaf39f> in <module>()
----> 1 {[x]:[x,x+1] for x in range(5)}
<ipython-input-30-32f94dcaf39f> in <dictcomp>(.0)
----> 1 {[x]:[x,x+1] for x in range(5)}
TypeError: unhashable type: 'list'
In [31]: {(x,):[x,x+1] for x in range(5)}
Out[31]: {(0,): [0, 1], (1,): [1, 2], (2,): [2, 3], (3,): [3, 4], (4,): [4, 5]}
In [32]: {chr(0x41+x):x**2 for x in range(5)}
Out[32]: {'A': 0, 'B': 1, 'C': 4, 'D': 9, 'E': 16}
In [33]: {str(x):y for x in range(3) for y in range(4)} #等价于如下
Out[33]: {'0': 3, '1': 3, '2': 3}
In [34]: ret={}
In [36]: for i in range(3):
...: for j in range(4):
...: ret[str(i)]=j
...:
...:
In [37]: ret
Out[37]: {'0': 3, '1': 3, '2': 3}
python2引入列表解析式;
python3引入生成器表达式;
python3引入集合解析式、字典解析式、并迁移到了2.7;
一般来说,要多应用解析式、简短、高效;
如果一个解析式非常复杂,难以读懂,要考虑拆解成for循环;
生成器和迭代器是不同的对象,但都是可迭代对象;
iter(iterable),将一个可迭代对象封装成一个迭代器;
next(iterator),取元素,对一个迭代器取下一个元素,如果元素全部取完,再next()会抛StopIteration异常;
可迭代对象:
能够通过迭代一次次返回不同元素的对象,所谓相同不是指值是否相同,而是元素在容器中是否是同一个,如list中值可重复;
可以迭代,但是未必有序,未必可索引;
可迭代对象有,list,tuple,string,bytes,bytearray,range,set,dict,iterator等;
可用成员运算符in,not in,in本质上就是在遍历对象;
迭代器:
特殊的对象,一定是可迭代对象,具备可迭代对象的特征;
通过iter(iterable)把一个可迭代对象封装成迭代器;
通过next()迭代迭代器对象;
生成器对象,就是迭代器对象;
迭代器不一定是生成器;
转载于:https://blog.51cto.com/jowin/2388530