设为首页 加入收藏

TOP

Python推导式详解
2023-07-26 08:18:16 】 浏览:86
Tags:Python

列表推导式是一种快速生成列表的方式。它一般用“[]"括起来,例如


这是一种最基本的用法,列表推导式先执行for循环,再把遍历的元素(或者对元素的一些计算表达式)作为列表的元素返回一个列表。


它就相当于


我们可以用列表推导快速初始化一个二维数组


用下面的式子就可以得到这个二维数组


列表推导式有很多种形式


这种生成的元素个数不会少,只是根据for循环的结果使用不同的表达式


这种会只取符合条件的元素,所以元素个数跟条件相关


假如我们展开一个二维矩阵,如下面的m,我们可以用嵌套循环实现。


用列表推导,最外层的for循环得到的row,可以在内层中使用


再比如下面这个例子


列表推导的用法比较灵活,我们不一定要把所有的都掌握,但是要能看懂。


集合推导的语法与列表推导一样,只是它是用”{}“,而且,集合会自动去重


字典推导的语法也与其他的类似,只不过在最前面的格式是key:value,而且也是会去重


既然用[]就能做列表推导,那用()是不是就能做元组推导了?不是的,因为()被用在了一种特殊的对象上:生成器(generator)。


生成器是一个顺序产生元素的对象,只能顺序访问,只能前进,而且只能遍历一次。


可以使用next()函数取下一个元素,取不到就会报StopIteration异常,也可以使用for循环遍历。


生成式没法用下标访问,用next访问直到报异常


用for循环遍历


先用next访问,再用for循环


我们可以加上list,tuple,set等做强转,但是list和set就没必要了,如果想初始化成tuple,就用tuple做强转。强转的时候不需要再加多余的括号。


生成式是惰式计算的,就是你确实用到这个元素了,它才去计算,好处就是节省了内存,但是坏处是不能随机访问。


我们用timeit模块去比较一下性能。


执行结果如下:


可见循环的方式比推导式慢了一倍,为什么会有这个问题呢?我们直接反编译看这两个的区别,用dis模块可以反编译Python代码,产生字节码。


源代码及行数如下


Python推导式详解


getlist1的反编译如下,左边红色对应源代码的行数,蓝色圈内就是第6行代码对应的字节码,我们可以看到,它有一个传参并且调用方法append的过程,调用函数的代价是比较大的。


Python推导式详解


再来看一下列表推断的反编译结果


Python推导式详解


首先从字节码数量上来比列表推断就比用循环调append要少的多,而且列表推断没有使用方法调用,直接用了这个指令LIST_APPEND,在Python官网上的解释是这样的。


Python推导式详解


实际上这个解释是有误导性,字节码中使用LIST_APPEND和在Python代码中调用append是完全不一样的,只不过这种底层的东西没有很多人关心,它们的功能是一样的。在2008年的时候就有人给Python代码提patch,希望能自动将list.append()进行优化,直接优化成LIST_APPEND而不是通过函数调用,但是目前还没被采纳。


Python推导式详解


提出者希望能在编译的时候加一些选项,比如像gcc可以使用-O1,-O2等进行不同级别的优化,但是目前CPython是没有这些选项的,因为大多数的Python开发者并不关心性能。


如果我们把上面的列表换成集合或者字典,差别会更大,所以能用推导式的地方尽量用推导式,可以提高性能。


其实这两个并不具备可比性,因为生成的结果并不是一个东西。我们可以很容易的预测,产生生成器的推导式性能要好于列表推导式,但是用的时候生成器就不如列表了。


执行结果:


生成器产生的性能远大于列表,但是遍历的时候不如列表,但是总体上看好像生成器好。不过不要忘了,生成器不能随机访问,而且只能用一次。所以这两种对象,就是在合适的地方用合适的类型,不一定哪一种比哪一种更好。



】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇使用PyQt5和Qt Designer创建Pytho.. 下一篇Linux TCP滑动窗口代码简述

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目