防伪码:忘情公子著
什么是列表解析?
列表解析就是根据已有列表,高效生成新列表的方式
列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中
语法:
[expression for iter_var in iterable] [expression for iter_var in iterable if cond_expr]
例:
In [1]: L = [i**2 for i in xrange(9)]
In [2]: print L [0, 1, 4, 9, 16, 25, 36, 49, 64]
假设现在有一个列表list1,需要取得列表list1中每一个元素的平方,并生成一个新列表,可以这样做:
In [3]: list1 = [1,2,3,4,5,6,7,8] In [4]: list2 = [i**2 for i in list1] In [5]: print list2 [1, 4, 9, 16, 25, 36, 49, 64]
只把list1中元素值大于或等于3的计算机其平方,并生成新列表,可以这样做:
In [6]: list3 = [i**2 for i in list1 if i >= 3] In [7]: print list3 [9, 16, 25, 36, 49, 64]
列表解析能够使用比for循环快近一倍的方式基于已有的列表来生成新列表
求1到10范围内10个数字的平方除以2的结果:
In [8]: for i in [i**2 for i in xrange(1,11)]: ...: print i / 2 ...: 0 2 4 8 12 18 24 32 40 50
返回1到10范围内所有偶数的平方除以2的结果:
In [9]: for i in [i**2 for i in xrange(1,11) if i %2 == 0]: ...: print i / 2 ...: 2 8 18 32 50
把/root目录下所有以.log结尾的文件取出来,生成一个新列表:
In [10]: import os In [11]: filelist = [i for i in os.listdir("/root") if i.endswith(".log")] In [12]: print filelist ['install.log']
把/etc目录下所有目录取出来,生成一个新列表:
In [13]: directory1 = [i for i in os.listdir("/etc") if os.path.isdir("/etc/"+i)] In [14]: print directory1 ['pkcs11', 'sasl2', 'xml', 'pear', 'terminfo', 'iscsi', 'sysconfig', 'security', 'statetab.d', 'NetworkManager', '.java', 'rc4.d', 'gcrypt', 'xinetd.d', 'ssh', 'httpd', 'dhcp', 'php.d', 'rc6.d', 'rpm', 'cron.daily', 'audit', 'selinux', 'depmod.d', 'dracut.conf.d', 'ntp', 'xdg', 'init', 'init.d', 'ConsoleKit', 'pm', 'yum', 'openldap', 'sudoers.d', 'logrotate.d', 'lxc', 'ppp', 'ld.so.conf.d', 'rwtab.d', 'dbus-1', 'gnupg', 'cron.weekly', 'sgml', 'pki', 'rc2.d', 'modprobe.d', 'audisp', 'exim', 'blkid', 'profile.d', 'cron.hourly', 'default', 'opt', 'rc0.d', 'ssl', 'fonts', 'sysctl.d', 'iproute2', 'X11', 'rc1.d', 'plymouth', 'rc.d', 'yum.repos.d', 'polkit-1', 'cron.monthly', 'pango', 'pam.d', 'rsyslog.d', 'prelink.conf.d', 'alternatives', 'rc3.d', 'makedev.d', 'popt.d', 'docker', 'udev', 'gconf', 'lvm', 'cgconfig.d', 'cron.d', 'chkconfig.d', 'bash_completion.d', 'skel', 'multipath', 'rc5.d']
在使用列表解析时,for循环还可以嵌套for循环。举例说明:
假设现在有两个列表list1和list2,现在要实现两个列表的元素交叉相乘,可以这样做:
In [15]: list1 = ['x','y','z'] In [16]: list2 = [1,2,3] In [17]: list3 = [(i,j) for i in list1 for j in list2] In [18]: print list3 [('x', 1), ('x', 2), ('x', 3), ('y', 1), ('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]
接下来实现当list2中元素值不为1时与list1交叉相乘,可以这样做:
In [19]: list4 = [(i,j) for i in list1 for j in list2 if j != 1] In [20]: print list4 [('x', 2), ('x', 3), ('y', 2), ('y', 3), ('z', 2), ('z', 3)]
列表解析会直接返回一个新列表,如果某个原列表里面的元素非常多,而列表解析又以几何倍数向上增长以后,就会极其占用内存,如此将导致效率低下。
但是列表生成以后,一般一次只取一个元素,而for循环一次只遍历迭代其中的一个元素,基于此,使用直接生成一个列表的方式如此占用内存是极其不好的。
由此我们可以对列表解析作一个扩展,就是把[]变成(),这就叫做生成器
生成器和列表解析的关系就相当于xrange和range的关系,它可以让我们使用一个表达式,一次只生成计算出一个值,叫惰性计算方式。
生成器不像列表解析一样,不管你用不用直接就生成了。生成器仅仅是你调用一次,它就可以返回一个,再调用一次,再返回一个。
生成器表达式并不真正创建数字列表,而是返回一个生成器对象,此对象在每次计算出一个条目后,把这个条目“产生”(yield)出来.生成器表达式使用了“惰性计算”或称作“延迟求值”的机制
当序列过长,并且每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析
生成器特点:
1、只有在调用时才会生成相对应的数据
2、只记录当前位置,无法向前回溯,只能一步步往后走
3、可以通过__next__()方法一次取一个值
4、可以通过for循环取得所有值
生成器表达式语法:
(expr for iter_var in iterable) (expr for iter_var in iterable if cond_expr)
生成器生成方法:
1、通过列表解析进行生成
[ i*2 for i in range(10) ]
2、通过函数生成(这里用著名的裴波那契数列来举例)
def fib(max): count,a,b = 0,0,1 while count < max: yield b a,b = b,a+b count += 1 return 'done'
生成器的return返回值包含在异常当中,为避免程序抛出异常,仅通过捕捉异常的方式才能取得return返回值。
yield保存了函数的中断状态。
生成器是什么情况下会用到呢?这里通过一个例子来说明一下:
生成器可以实现在单线程(串行)的情况下实现并发运算的效果
生成器的__next__()方法只调用生成器的状态而不传值;
生成器的send()方法在调用生成器的状态的同时给生成器传一个值
import time def cut(cutter): print('%s 已经准备好撕纸了。'% cutter) num = 1 while True: paper = yield print('第%s张%s刚做好了,已经被%s撕了。'% (num,paper,cutter)) num += 1 def make(maker): cutter1 = cut('撕纸员1') cutter2 = cut('撕纸员2') cutter1.__next__() cutter2.__next__() print('%s已经准备好做纸了。'% maker) for i in range(1,11): time.sleep(1) print('%s已经做好了1张纸'% maker) cutter1.send(i) cutter2.send(i) make('Tom')
返回1到10范围内所有正整数的平方:
In [21]: g1 = (i**2 for i in range(1,11)) In [22]: g1.next() Out[22]: 1 In [23]: g1.next() Out[23]: 4 In [24]: g1.next() Out[24]: 9 In [25]: g1.next() Out[25]: 16 In [26]: g1.next() Out[26]: 25 In [27]: g1.next() Out[27]: 36 In [28]: g1.next() Out[28]: 49 In [29]: g1.next() Out[29]: 64 In [30]: g1.next() Out[30]: 81 In [31]: g1.next() Out[31]: 100 In [32]: g1.next() --------------------------------------------------------------------------- StopIteration Traceback (most recent call last)in () ----> 1 g1.next() StopIteration:
返回1到10范围内所有正整数的平方除以2的结果:
In [33]: for i in (i**2 for i in range(1,11)): ...: print i / 2 ...: 0 2 4 8 12 18 24 32 40 50
产生偏移和元素,使用enumerate函数:
range可在非完备遍历中用于生成索引偏移,而非偏移处的元素
如果同时需要偏移索引和偏移元素,则可以使用enumerate()函数,此内置函数返回一个生成器对象,例:
In [35]: url = 'www.python.org' In [36]: g2 = enumerate(url) In [37]: g2.next() Out[37]: (0, 'w') In [38]: g2.next() Out[38]: (1, 'w') In [39]: g2.next() Out[39]: (2, 'w') In [40]: g2.next() Out[40]: (3, '.') In [41]: g2.next() Out[41]: (4, 'p') In [42]: g2.next() Out[42]: (5, 'y') In [43]: g2.next() Out[43]: (6, 't') In [44]: g2.next() Out[44]: (7, 'h') In [45]: g2.next() Out[45]: (8, 'o') In [46]: g2.next() Out[46]: (9, 'n') In [47]: g2.next() Out[47]: (10, '.') In [48]: g2.next() Out[48]: (11, 'o') In [49]: g2.next() Out[49]: (12, 'r') In [50]: g2.next() Out[50]: (13, 'g') In [51]: g2.next() --------------------------------------------------------------------------- StopIteration Traceback (most recent call last)in () ----> 1 g2.next() StopIteration: