鸦鸦 发表于 2018-8-16 07:26:28

python之列表解析与生成器

  防伪码:忘情公子著
  什么是列表解析?
  列表解析就是根据已有列表,高效生成新列表的方式
  列表解析是python迭代机制的一种应用,它常用于实现创建新的列表,因此要放置于[]中
  语法:
  

  例:
In : L = In : print L  

  假设现在有一个列表list1,需要取得列表list1中每一个元素的平方,并生成一个新列表,可以这样做:
In : list1 =   

  
In : list2 =
  

  
In : print list2
  

  只把list1中元素值大于或等于3的计算机其平方,并生成新列表,可以这样做:
In : list3 =   

  
In : print list3
  

  列表解析能够使用比for循环快近一倍的方式基于已有的列表来生成新列表
  求1到10范围内10个数字的平方除以2的结果:
In : for i in :  
   ...:   print i / 2
  
   ...:
  
0
  
2
  
4
  
8
  
12
  
18
  
24
  
32
  
40
  
50
  返回1到10范围内所有偶数的平方除以2的结果:
In : for i in :  
   ...:         print i / 2
  
   ...:
  
2
  
8
  
18
  
32
  
50
  把/root目录下所有以.log结尾的文件取出来,生成一个新列表:
In : import os  

  
In : filelist =
  

  
In : print filelist
  
['install.log']
  把/etc目录下所有目录取出来,生成一个新列表:
In : directory1 =   

  
In : 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 : list1 = ['x','y','z']  

  
In : list2 =
  

  
In : list3 = [(i,j) for i in list1 for j in list2]
  

  
In : print list3
  
[('x', 1), ('x', 2), ('x', 3), ('y', 1), ('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]
  接下来实现当list2中元素值不为1时与list1交叉相乘,可以这样做:
In : list4 = [(i,j) for i in list1 for j in list2 if j != 1]  

  
In : 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 : g1 = (i**2 for i in range(1,11))  

  
In : g1.next()
  
Out: 1
  

  
In : g1.next()
  
Out: 4
  

  
In : g1.next()
  
Out: 9
  

  
In : g1.next()
  
Out: 16
  

  
In : g1.next()
  
Out: 25
  

  
In : g1.next()
  
Out: 36
  

  
In : g1.next()
  
Out: 49
  

  
In : g1.next()
  
Out: 64
  

  
In : g1.next()
  
Out: 81
  

  
In : g1.next()
  
Out: 100
  

  
In : g1.next()
  
---------------------------------------------------------------------------
  
StopIteration                           Traceback (most recent call last)
  
<ipython-input-32-9066a8f18086> in <module>()
  
----> 1 g1.next()
  

  
StopIteration:
  返回1到10范围内所有正整数的平方除以2的结果:
In : 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 : url = 'www.python.org'  

  
In : g2 = enumerate(url)
  

  
In : g2.next()
  
Out: (0, 'w')
  

  
In : g2.next()
  
Out: (1, 'w')
  

  
In : g2.next()
  
Out: (2, 'w')
  

  
In : g2.next()
  
Out: (3, '.')
  

  
In : g2.next()
  
Out: (4, 'p')
  

  
In : g2.next()
  
Out: (5, 'y')
  

  
In : g2.next()
  
Out: (6, 't')
  

  
In : g2.next()
  
Out: (7, 'h')
  

  
In : g2.next()
  
Out: (8, 'o')
  

  
In : g2.next()
  
Out: (9, 'n')
  

  
In : g2.next()
  
Out: (10, '.')
  

  
In : g2.next()
  
Out: (11, 'o')
  

  
In : g2.next()
  
Out: (12, 'r')
  

  
In : g2.next()
  
Out: (13, 'g')
  

  
In : g2.next()
  
---------------------------------------------------------------------------
  
StopIteration                           Traceback (most recent call last)
  
<ipython-input-51-6d69cefe8ba3> in <module>()
  
----> 1 g2.next()
  

  
StopIteration:
页: [1]
查看完整版本: python之列表解析与生成器