设为首页 收藏本站
查看: 1283|回复: 0

[经验分享] python之列表解析与生成器

[复制链接]

尚未签到

发表于 2018-8-16 07:26:28 | 显示全部楼层 |阅读模式
  防伪码:忘情公子著
  什么是列表解析?
  列表解析就是根据已有列表,高效生成新列表的方式
  列表解析是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)
  
<ipython-input-32-9066a8f18086> in <module>()
  
----> 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)
  
<ipython-input-51-6d69cefe8ba3> in <module>()
  
----> 1 g2.next()
  

  
StopIteration:

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-552377-1-1.html 上篇帖子: CentOS 6.7安装python3.5 下篇帖子: python3_08.动动mysql
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表