这篇文章主要介绍Python中的两个非常好用的语法糖,解析式 和 生成器,如果运用熟练的话,可以极大的减少代码的书写量
列表解析式
语法:
- [返回值 for 元素 in 可迭代对象 if 条件]
- 使用中括号[],内部是for循环,if条件语句可选
- 返回一个新的列表
其实语法很简单,主要看例子来了解如何书写一些解析式
例子1:生成一个列表,元素0~9,对每一个元素自增1后求平方返回新列表
如果按照常规的for..in语句的话,它是这样的
>>> l1 = list(range(10))
>>> l2 = []
>>> for i in l1:
l2.append((i+1)**2)
>>> print(l2)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
但是如果换成 解析式来写的话,代码回极大化的减少,它看起来是这样的
>>> l1 = list(range(10))
>>> l2 = [(i+1)**2 for i in l1]
>>> print(l2)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
怎么理解呢?你可以这样想,首先,按照语法规则,表达式是[]加内层套for..in的结构是一种解析式, [(i+1)**2 for i in l1] 这种解析分两步,第一步,for i in l1,做for..in遍历,把得到的每一个 i 值,传递给表达式 (i+1)**2,然后生成的数据,再加入 [] 列表结构中,最后把 [] 列表赋值给 l2
再看一个例子
例子2:获取10以内的偶数
首先常规for..in写法:
>>> even = []
>>> for x in range(10):
if x % 2 == 0:
even.append(x)
解析式写法
>>> even = [x for x in range(10) if x % 2 == 0]
这种例子呢,是带条件判断的解析式,我们也来拆,首先把 for x in range(10) if x % 2 == 0 拆出来,其实这就是一个判断偶数的for..in循环 类似于常规的写法:
for x in range(10):
if x % 2 == 0
只不过 for x in range(10) if x % 2 == 0 表达式会把,满足条件的 x 逐个返回,所以:
>>> even = [x for x in range(10) if x % 2 == 0]
>>> even
[0, 2, 4, 6, 8]
多条件判断的解析式: [expr for item in iterable if cond1 if cond2]
例子3:20以内,既能被2整除又能被3整除的数
>>> ret = [i for i in range(20) if i%2==0 and i%3==0]
或者
>>> ret = [i for i in range(20) if i%2==0 if i%3==0]
双层for..in 语句的解析式:[expr for i in iterable1 for j in iterable2 ]
例: [(x, y) for x in 'abcde' for y in range(3)] ,输出什么
首先我们把第一层for..in 拆出来 for x in 'abcde' ,每迭代一次,返回一个 x 紧接着 再执行 for y in range(3) 迭代 3 次 y,所以,迭代值 产生顺序为 x -> 'a' y-> 0,x->'a' y -> 1,x -> 'a' y -> 2;
x -> 'b' y-> 0, x -> 'b' y -> 1, x -> 'b' y -> 2 ........ 所以 输出:
>>> [(x, y) for x in 'abcde' for y in range(3)]
[('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2), ('c', 0), ('c', 1), ('c', 2), ('d', 0), ('d', 1), ('d', 2), ('e', 0), ('e', 1), ('e', 2)]
请问下面输出什么:
[(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
首先分析 第一层for..in 循环 for i in range(7) if i>4 ,代表,i 从 0 遍历到 6,但只有 i >4 时才走下一个 for..in循环 ,而第二个for..in循环 for j in range(20,25) if j>23,代表 j 从20 遍历到24,但只有j > 23 也就是 j == 24时才返回值,所以这个列表解析式,生成值的顺序为: i == 5 j == 24, i == 6 j == 24 所以:
>>> [(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
[(5, 24), (6, 24)]
例:有一个列表lst = [1,4,9,16,2,5,10,15],生成一个新列表,要求新列表元素是lst相邻2项的和
>>> lst = [1,4,9,16,2,5,10,15]
>>> sum = [lst[i] + lst[i+1] for i in range(len(lst) - 1)]
>>> sum
[5, 13, 25, 18, 7, 15, 25]
例:"0001.abadicddws" 是ID格式,要求ID格式是以点号分割,左边是4位从1开始的整数,右边是10位随机小写英文字母。请依次生成前100个ID的列表
第一步,先生成“0001”格式的字符串
>>> ["{:04}".format(i) for i in range(1,101)]
>>>
['0001', '0002', '0003', '0004', '0005', '0006', '0007', '0008', '0009', '0010', '0011', '0012', '0013', '0014', '0015', '0016', '0017', '0018', '0019', '0020', '0021', '0022', '0023', '0024', '0025', '0026', '0027', '0028', '0029', '0030', '0031', '0032', '0033', '0034', '0035', '0036', '0037', '0038', '0039', '0040', '0041', '0042', '0043', '0044', '0045', '0046', '0047', '0048', '0049', '0050', '0051', '0052', '0053', '0054', '0055', '0056', '0057', '0058', '0059', '0060', '0061', '0062', '0063', '0064', '0065', '0066', '0067', '0068', '0069', '0070', '0071', '0072', '0073', '0074', '0075', '0076', '0077', '0078', '0079', '0080', '0081', '0082', '0083', '0084', '0085', '0086', '0087', '0088', '0089', '0090', '0091', '0092', '0093', '0094', '0095', '0096', '0097', '0098', '0099', '0100']
第二步,生成“abadicddws”格式的字符串
>>> "{}".format("".join([chr(random.randint(97,122)) for j in range(10)]))
>>>
'jsfujismmz'
最终是这样的:
>>> ["{:04}.{}".format(i,"".join([chr(random.randint(97,122)) for j in range(10)])) for i in range(1,101)]
>>>
['0001.hrnzpxrggj', '0002.hcewoyvhib', '0003.isrzlcilqa', '0004.xjmerfvqeu', '0005.bdpaptyncm', '0006.gncrndwicp', '0007.qpvsqdteyk', '0008.oqlrbeanef', '0009.emyzzvwegi', '0010.thrmlbggtb', '0011.zrceabrnrk', '0012.mlaoxftpmd', '0013.dkgpzoqueh', '0014.cbcjiimqux', '0015.aihwjnaitn', '0016.shtwzfuxjj', '0017.sfpvteyqvc', '0018.pnrclhcpzj', '0019.ajrdzdrwqc', '0020.rdfgraokuy', '0021.bkqkxxmaik', '0022.gkzcypihjr', '0023.dmkibhjefk', '0024.nwarcujjhk', '0025.nczsuocycp', '0026.xzsayeioeb', '0027.sepmzrfvul', '0028.pacwehaakh', '0029.jwtjveezxx', '0030.axnanrtuol', '0031.fmmaygfkzm', '0032.gghcwsiltf', '0033.sehpvgicwf', '0034.llbwdvukwz', '0035.nkbklakfdg', '0036.qfnitnflko', '0037.jjjmdstndz', '0038.olcqhpnjor', '0039.mocvpchnno', '0040.hjcssgrkur', '0041.dopvutaiie', '0042.zrpsgtwqlx', '0043.ixhdkzluky', '0044.vayfdgpjir', '0045.rsjvgseyup', '0046.aggwfpykqr', '0047.rngjsfgqwh', '0048.ppvxzmdrlr', '0049.lhjbedhhlr', '0050.gvrkhwgaom', '0051.ovlggwcbwz', '0052.fguiywhwgw', '0053.rkoncsjlhj', '0054.bkrekesbxl', '0055.zwlkfrsqyx', '0056.irdqiripah', '0057.uknwmstypv', '0058.nvfvknebrh', '0059.csthvpotmf', '0060.szweqvbigu', '0061.bvwsyooloj', '0062.koaavoxuke', '0063.ozevzhbkmw', '0064.oebfodmujx', '0065.rvldiiflys', '0066.espalqvdrz', '0067.suhegwycvh', '0068.trhylwfreb', '0069.ykktjablxy', '0070.ryfzljcnby', '0071.mjodycvqzd', '0072.tdgfpkvzjm', '0073.vqbboclptg', '0074.nkjpgjmqpc', '0075.kisxtvlhwi', '0076.nzvjmrrtpn', '0077.baqyccriev', '0078.eqsqesjcmn', '0079.yxzwxohcvh', '0080.pmorbqhavh', '0081.jjeywgmkai', '0082.ucglygdhbj', '0083.xqbywtjgod', '0084.gsbzriptei', '0085.kzobpynbit', '0086.bniztmnezo', '0087.wlebbvewhp', '0088.dbldkehstv', '0089.lysirrrqfp', '0090.xagrlbeenq', '0091.zrxxpoftll', '0092.rndfbedrnr', '0093.jffsblbtvb', '0094.nnumtcifns', '0095.kbjaqelcbu', '0096.qshlogpdho', '0097.mhtmycgzza', '0098.dkpphqmuya', '0099.lfvxrakcwt', '0100.ewrhmzswfq']
所以,看到这里列表解析式有点眉目了吧!!!!!
集合解析式
语法
1.{返回值 for 元素 in 可迭代对象 if 条件}
2.列表解析式的中括号换成大括号{}就行了
3.立即返回一个集合
>>> {(x,x+1) for x in range(10)}
{(0, 1), (1, 2), (7, 8), (6, 7), (4, 5), (5, 6), (8, 9), (9, 10), (2, 3), (3, 4)}
字典解析式
语法
1.{返回值 for 元素 in 可迭代对象 if 条件}
2.列表解析式的中括号换成大括号{}就行了
3.使用key:value形式
4.立即返回一个字典
>>> {x:(x,x+1) for x in range(10)}
{0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5), 5: (5, 6), 6: (6, 7), 7: (7, 8), 8: (8, 9), 9: (9, 10)}
>>> {str(x):y for x in range(3) for y in range(4)}
{'0': 3, '1': 3, '2': 3}
等价于
>>> ret = {}
>>> for x in range(3):
>>> for y in range(4):
ret[str(x)] = y
>>> ret
{'0': 3, '1': 3, '2': 3}
生成器表达式Generator expression
语法
1.(返回值 for 元素 in 可迭代对象 if 条件)
2.列表解析式的中括号换成小括号就行了
3.返回一个生成器
和列表解析式的区别
1.生成器表达式是按需计算(或称惰性求值、延迟计算),需要的时候才计算值
2.列表解析式是立即返回值
生成器
1.可迭代对象
2.迭代器
列表解析式 ===> g = ["{:04}".format(i) for i in range(1,11)]
1.立即计算
2.返回的不是迭代器,返回可迭代对象列表
3.从前到后走完一遍后,可以重新回头迭代
生成器 ===> g = ("{:04}".format(i) for i in range(1,11)) 可以用next()方法
1.延迟计算
2.返回迭代器,可以迭代
3.从前到后走完一遍后,不能回头
>>> g = ("{:04}".format(i) for i in range(1,11))
>>>> g
<generator object <genexpr> at 0x113267728>
>>> next(g)
'0001'
>>> next(g)
'0002'
>>> for i in g:
print(i)
0003
0004
0005
0006
0007
0008
0009
0010