Example A: Requirement: [1, 2, 3] --> [2, 4, 6] Solution: def maps(a): return [i*2 for i in a]
1-1 列表生成式 >>> a = [1,2,3] >>> a [1, 2, 3] >>> >>> [i*2 for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # for i in range(10) 这是一个循环,循环 10 次,i*2 中的 i 就是 for 循环中的 i # 把 for 循环中的临时变量 i 赋值到前面的 i*2 的 i 中,得到的结果,就是列表中的元素 # 这个列表 和 列表 a 的区别是:列表 a 是写死的,下面的 i*2 是可以进行操作的
1-1-1 # [i*2 for i in range(10)] 相当于 >>> a = [] >>> for i in range(10): ... a.append(i*2) ... >>> a [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] # 相当于至少 3 行代码; [i*2 for i in range(10)] 就叫 列表生成式 列表生成式的主要作用就是使代码更简洁
1-1-2 当然列表生成式也可以传函数,比如 >>> [func(i) for i in range(10)] 注: # 在 python2 上 range(10) 数据已经准备好了 # 在 python3 上 range(10) 是没有准备好的
Example B: Given a string of digits, you should replace any digit below 5 with '0' and any digit 5 and above with '1'. Return the resulting string. Solution A: def fake_bin(x): return ''.join['0' if int(a) < 5 else '1' for a in x] Solution B: def fake_bin(x): return ''.join('0' if int(a) < 5 else '1' for a in x) # 为什么Solution A 是[],而Solution B 中是 ()?
2-1 生成器 通过列表生成式,我们可以直接创理一个列表。 但是,受到内存限制,列表容量肯定是有限的。 如果仅需要访问前面几个元素,后面绝大多数元素占用的空间都白白浪费了。 所以, 如果列表元素可以按照某种算法推算出来 是否可以在循环的过程中不断推算出后续的元素呢? 这样就不必创建完整的list,从而节省大量的空间。 在Python中,这种一边循环一边计算的机制,称为生成器:generator。 要创建一个generator, 有很多种方法。 第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator; # 比如希望在循环的时候,循环到 列表的 第 4 个元素时,这个元素才刚生成; # 这样,就不用把所有数据都提前准备好了,就可以节省空间
2-1-1 >>> [i*2 for i in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> (i*2 for i in range(10)) <generator object <genexpr> at 0x0000027B0E6C3BC8> # 这就变成了一个生成器,对这个数据进行循环时,每循环一次就按此规律乘 2
2-1-2 >>> b = (i*2 for i in range(10)) >>> for i in b: ... print(i) 0 2 4 …… 18 >>> # 这里的数据量比较少,所以也许无法看出差异; # 但如果数据量达到100个以上,这种方法可以马上返回数据,这时,如果继续用以往的形式,就会感觉到慢了
2-1-3 >>> c = ( i*2 for i in range(100000000)) >>> c <generator object <genexpr> at 0x0000027B0E6F72C8> >>> # 事实上,这里并没有生成数据,只是返回了一个地址,除非访问这个地址,才会生成数据 # 如果不访问,这个数据就不会存在; # 列表则是把所有数据都准备好的; # 而生成器则是准备了一个算法,算法写好了一个规则,调用时,才会产生数据
2-1-4 # 现在想访问 c 的第 1000 个数据,前面的 999 个数据要被循环到,才能够调用; # 否则无法直接一下调用第 1000 个 >>> c[1000] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'generator' object is not subscriptable # 所以它不支持列表的那种切片;既然生成器不支持切片,那生成器能够支持什么呢? # 除了用 for 循环一个一个的取,还支持别的方式吗? # 没有,只能用 for 循环这一种方式获取
2-1-5 # 如果只访问 2-1-3 中的前两个数据,应该怎么做呢? # 生成器,有一个方法,叫做 __next__() 方法 >>> c = ( i*2 for i in range(100000000)) >>> for i in c: ... print(i) ... 0 2 4 …… 2210 2212 Traceback (most recent call last): File "<stdin>", line 2, in <module> KeyboardInterrupt >>> c.__next__() 2214 >>> c.__next__() 2216 >>> c.__next__() 2218 >>> c.__next__() 2220 >>> # 现在要回去取 2210,是不可以的,回去取是不行的;而且也没有任何相应的方法让你回到上一个 # 生成器只记住当前位置,它不知道前面,也不知道后面;前面用完了,就没了 # 所以既不能往前走,也不能往后退;只能一点一点的往后走
1 生成器 只有在调用时才会生成相应的数据 2 只记录当前位置 3 只有一个 __next__()方法。(在 python2.7 中是 next())
查看更多关于20210514 列表生成式与生成器的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did125926