美文网首页
2018-01-26-列表解析和生成器到底是啥?

2018-01-26-列表解析和生成器到底是啥?

作者: 0xC00005 | 来源:发表于2018-01-27 13:31 被阅读0次

    前言

    自从上次码风被某hub上的人吐槽【甘拜下风】之后,我就一直在研究如何如何把代码写的更短♂小精悍

    【NOI老毛病之能少打字就少打字......】

    由于之前一直都是思路写注释清晰向,初次接触列表解析什么的“短代码”又闻到了一股子曾经不惜一切减复杂度的味道(说实话没人会在乎那TLE的一秒两秒的嘿嘿嘿)

    正片

    先用正常的风格写一个生成列表的代码

    
    >>> for num in range(11):\
    
        lists.append(num)
    
    >>> lists
    
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    

    然后我们来看看可以如何删减代码,先从for循环的原理入手

    For循环的原理

    使用了BDFS(Baidu-FS)之后

    某南京大学的python讲座
    发现自己连for都不知道是什么......
    for 变量a in 另一个可迭代的变量:
        执行代码
    else:#当for结束之后
        执行代码
    

    什么是可迭代的对象呢?说白了就是可以被遍历的对象,像字符串,列表,字典等等,就是每一次更新之后可以改变数值的对象,类似于C里面的int,doubld和常量【忘记怎么打了】就都是不可迭代对象

    就像下面这样,不可迭代对象自定义列MyRange, for是不认的

    >>> class MyRange:
    ...     def __init__(self, num):
    ...         self.num = num
    ...
    >>> for i in MyRange(10):
    ...     print(i)
    ...
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'MyRange' object is not iterable
    

    所以综上所述,使用列表解析所需要的:
    for,表达式,可迭代对象,条件,方括号[ORZ]

    列表解析

    语法

    [变量a(添加条件)  for 同时也是可迭代变量的a in 一个可迭代的对象b if 表达式]
    

    1.你需要一对中/方括号【赶紧膜拜[FKH]大学神】
    2.在里面有一个表达式 例如i for 一个可迭代的变量i
    3.把i in到一个可迭代的对象里面
    5.别忘了加上冒号:【滑稽】

    加冒号会报错啊别真的加了啊喂~

    如上,上面一长串的代码就可以缩成:

    lists=[i for i in range(11)]#不需要事先定义Lists为空列表
    

    达成成就:在列表/数组里面写表达式

    在列表表达式里面添加条件

    如果我们需要生成1~11的奇数序列呢
    我猜大部分人应该都会想到.....

    lists=[i for i in range(1,11,2)]#不需要事先定义Lists为空列表
    

    是吗傻逼们?

    >>> lists=[i for i in range(1,11,2)]
    >>> lists
    [1, 3, 5, 7, 9]
    

    恭喜你不仅仅TLE还RE爆掉一个点

    这时候请返回上面看看在列表解析式里面如何高(zhuang)雅(Bi)的写条件判断语句

    #i+1是因为奇数从1开始,而列表从0生成
    >>> [i+1 for i in range(11) if i%2==0]
    [1, 3, 5, 7, 9, 11]
    

    生成器解析式

    请把方括号改成圆括号()
    好了你学会了?

    >>> (i+1 for i in range(11) if i%2==0)
    <generator object <genexpr> at 0x037C0120>
    

    列表解析和生成器语法对比

    #列表解析
    [expr for iter_var in iterable] 
    [expr for iter_var in iterable if cond_expr]
    
    #生成器
    (expr for iter_var in iterable) 
    (expr for iter_var in iterable if cond_expr)
    

    得到结论:没有区别

    那到底有什么区别,生成器解析的结果在哪里?

    生成器表达式并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。 生成器表达式使用了“惰性计算”(lazy evaluation,也有翻译为“延迟求值”,我以为这种按需调用call by need的方式翻译为惰性更好一些),只有在检索时才被赋值( evaluated),所以在列表比较长的情况下使用内存上更有效。

    结语

    好了不说了代码变短了但是谁都读不懂2333
    还是遵循import this 写代码得了
    还是参考一下别人的说明

    1. 当需要只是执行一个循环的时候尽量使用循环而不是列表解析,这样更符合python提倡的直观性。
      for item in sequence:
      process(item)
    2. 当有内建的操作或者类型能够以更直接的方式实现的,不要使用列表解析。
      例如复制一个列表时,使用:L1=list(L)即可,不必使用:L1=[x for x in L]
    3. 当序列过长, 而每次只需要获取一个元素时,使用生成器表达式。
    4. 列表解析的性能相比要比map要好,实现相同功能的for循环效率最差(和列表解析相比差两倍)。
    5. 列表解析可以转换为 for循环或者使用map(其中可能会用到filter、lambda函数)表达式,但是列表解析更为简单明了,后者会带来更复杂和深层的嵌套。

    参考资料?

    python中for循环的工作原理
    python 中的列表解析和生成表达式
    某南京大学的金牌网课?

    最后的最后

    去小姐姐的官网给颗星星吧~

    谢谢捧场( • ̀ω•́ )✧

    相关文章

      网友评论

          本文标题:2018-01-26-列表解析和生成器到底是啥?

          本文链接:https://www.haomeiwen.com/subject/tejnaxtx.html