前言

很多小伙伴应该都做过打印九九乘法表吧
你的代码是这样的呢

list=[]
for x in range(1,10):
list2=[]
for y in range(1,x+1):
list2.append('%s*%s=%-2s' % (y, x, x*y))
list.append(' '.join(list2))
print('\n'.join(list))

还是这样的呢

print('\n'.join([' '.join(['%s*%s=%-2s' % (y, x, x*y) for y in range(1, x+1)]) for x in range(1, 10)]))
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81

其实python一行代码还能这样

print('\n'.join([''.join([('Love'[(x-y) % len('Love')] if ((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3 <= 0 else ' ') for x in range(-30,30)]) for y in range(30, -30, -1)]))

veLoveLov veLoveLov
eLoveLoveLoveLove eLoveLoveLoveLove
veLoveLoveLoveLoveLoveLoveLoveLoveLoveLov
veLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveL
veLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLov
eLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLove
LoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveL
oveLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLo
veLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLov
eLoveLoveLoveLoveLoveLoveLoveLoveLoveLoveLove
oveLoveLoveLoveLoveLoveLoveLoveLoveLoveLove
eLoveLoveLoveLoveLoveLoveLoveLoveLoveLove
LoveLoveLoveLoveLoveLoveLoveLoveLoveLoveL
eLoveLoveLoveLoveLoveLoveLoveLoveLove
oveLoveLoveLoveLoveLoveLoveLoveLove
eLoveLoveLoveLoveLoveLoveLoveLove
veLoveLoveLoveLoveLoveLoveLov
oveLoveLoveLoveLoveLoveLo
LoveLoveLoveLoveLoveL
LoveLoveLoveLov
LoveLoveL
Lov
v

它们都用到了推导式,接下来让我们看看推导式究竟是怎么一回事

1.推导式分类与用法

1.1 列表推导

列表推导式(又称列表解析式)提供了一种简明扼要的方法来创建列表。 它的结构是在一个中括号里包含一个表达式,然后是一个for语句,然后是0个或多个for或者if语句。那个表达式可以是任意的,意思是你可以在列表中放入任意类型的对象。返回结果将是一个新的列表,在这个以if和for语句为上下文的表达式运行完成之后产生。

>>> [i for i in range(10)]
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]

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

>>> l = []
>>> for i in range(10):
... l.append(i*i)
...
>>>

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

m = [[0,0,0],
[0,0,0],
[0,0,0]
] n = []
for row in range(3):
r = []
for col in range(3):
r.append(0)
n.append(r)
print(n)

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

>>> [[0]*3 for i in range(3)]
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

列表推导式有很多种形式
for循环前面加if…else…
这种生成的元素个数不会少,只是根据for循环的结果使用不同的表达式

# 如果i是5的倍数,结果是i,否则就是0
>>> [i if i % 5 == 0 else 0 for i in range(20)]
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 10, 0, 0, 0, 0, 15, 0, 0, 0, 0] # 如果是偶数就加100,奇数就减100
>>> [i+100 if i % 2 == 0 else i-100 for i in range(10)]
[100, -99, 102, -97, 104, -95, 106, -93, 108, -91]

for循环后面加if…
这种会只取符合条件的元素,所以元素个数跟条件相关

# for循环的结果只选择是偶数的
>>> [i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]
# for循环的结果只选择是2和3的倍数的
>>> [i for i in range(10) if i % 2 == 0 and i % 3 == 0]
[0, 6]
# for循环的结果只选择偶数,并且应用str函数
>>> [str(i) for i in range(10) if i % 2 == 0]
['0', '2', '4', '6', '8']

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

m = [[1,2,3],
[4,5,6],
[7,8,9]
] n = []
for row in m:
for col in row:
n.append(col)
print(n)

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

m = [[1,2,3],
[4,5,6],
[7,8,9]
]
n = [col for row in m for col in row]
print(n)

再比如下面这个例子

>>> [a + b for a in '123' for b in 'abc']
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']

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

>>> dic = {"k1":"v1","k2":"v2"}
>>> a = [k+":"+v for k,v in dic.items()]
>>> a
['k1:v1', 'k2:v2']

1.2 集合推导

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

>>> { i for i in range(10)}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> { 0 if i % 2 == 0 else 1 for i in range(10)}
{0, 1}

1.3 字典推导

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

>>> { i : i.upper() for i in 'hello world'}
{'h': 'H', 'e': 'E', 'l': 'L', 'o': 'O', ' ': ' ', 'w': 'W', 'r': 'R', 'd': 'D'}
>>> { str(i) : i*i for i in range(10)}
{'0': 0, '1': 1, '2': 4, '3': 9, '4': 16, '5': 25, '6': 36, '7': 49, '8': 64, '9': 81}

1.4 元组推导?不存在的

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

>>> a = (i for i in range(10))
>>> print(a)
<generator object <genexpr> at 0x000001A6100869C8>
>>> type(a)
<class 'generator'>

生成器是一个顺序产生元素的对象,只能顺序访问,只能前进,而且只能遍历一次。
可以使用next()函数取下一个元素,取不到就会报StopIteration异常,也可以使用for循环遍历。
生成式没法用下标访问,用next访问直到报异常

>>> a = (i for i in range(0,2))
>>> a[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not subscriptable
>>> next(a)
0
>>> next(a)
1
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

用for循环遍历

>>> a = (i for i in range(0,2))
>>> for i in a:
... print(i)
...
0
1

先用next访问,再用for循环

>>> a = (i for i in range(0,3))
>>> next(a)
0
>>> for i in a:
... print(i)
...
1
2

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

>>> a = tuple(i for i in range(0,3))
>>> a
(0, 1, 2)
>>> a = tuple( (i for i in range(0,3)) )
>>> a
(0, 1, 2)

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

2.推导式的性能

2.1 列表推导式与循环的性能

可能大部分小伙伴以为,推导式稍微有点复杂,是不是性能比常规的差呢?我们用timeit模块去比较一下性能。

import timeit

def getlist1():
l = []
for i in range(10000):
l.append(i)
return l def getlist2():
return [i for i in range(10000)] # 各执行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000) print('循环方式:',t1)
print('推导式方式:',t2)

执行结果如下:

循环方式: 5.343517699991935
推导式方式: 2.6003115000057733

可见循环的方式比推导式慢了一倍

2.2 列表推导式与生成器推导式的性能

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

import timeit

def getlist1():
return [i for i in range(10000)] def getlist2():
return (i for i in range(10000)) # 各执行10000次
t1 = timeit.timeit('getlist1()',"from __main__ import getlist1", number=10000)
t2 = timeit.timeit('getlist2()',"from __main__ import getlist2", number=10000) print('列表:',t1)
print('生成器:',t2) def getlist11():
a = [i for i in range(10000)]
sum = 0
for i in a:
sum += i def getlist22():
a = (i for i in range(10000))
sum = 0
for i in a:
sum += i # 各执行10000次
t1 = timeit.timeit('getlist11()',"from __main__ import getlist11", number=10000)
t2 = timeit.timeit('getlist22()',"from __main__ import getlist22", number=10000) print('列表:',t1)
print('生成器:',t2)

执行结果:

列表: 2.5977418000111356
生成器: 0.006076899997424334
列表: 6.336311199993361
生成器: 9.181903699995019

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

Python推导式详解,带你写出比较精简酷炫的代码的更多相关文章

  1. Python 推导式详解

    各种推导式详解 推导式的套路 之前我们已经学习了最简单的列表推导式和生成器表达式.但是除此之外,其实还有字典推导式.集合推导式等等. 下面是一个以列表推导式为例的推导式详细格式,同样适用于其他推导式. ...

  2. python数据类型详解及列表字典集合推导式详解

    一.运算符 Python语言支持以下类型的运算符: 算术运算符 如: #!/usr/bin/env python # -*- coding:utf-8 -*- a = 5 b = 6 print(a ...

  3. python列表推导式详解

    推导式是Python中很强大的.很受欢迎的特性,具有语言简洁,简化代码,速度快等优点.推导式包括:1.列表推导式2.字典推导式3.集合推导式4.嵌套列表推导式注意: 字典和集合推导是最近才加入到Pyt ...

  4. day14 python各种推导式详解

    推导式的套路 之前我们已经学习了最简单的列表推导式和生成器表达式.但是除此之外,其实还有字典推导式.集合推导式等等. 下面是一个以列表推导式为例的推导式详细格式,同样适用于其他推导式. variabl ...

  5. python列表推导式详解 列表推导式详解 字典推导式 详解 集合推导式详解 嵌套列表推导式详解

    推导式是Python中很强大的.很受欢迎的特性,具有语言简洁,简化代码,速度快等优点.推导式包括:1.列表推导式2.字典推导式3.集合推导式4.嵌套列表推导式注意: 字典和集合推导是最近才加入到Pyt ...

  6. python全栈开发从入门到放弃之推导式详解

    variable = [out_exp_res for out_exp in input_list if out_exp == 2] out_exp_res: 列表生成元素表达式,可以是有返回值的函数 ...

  7. python第七篇:Python 列表操作详解

    Python列表操作详解 list函数 list()   #生成一个空的列表 list(iterable)  #用可迭代对象初始化一个列表 列表的 and 运算和 or 运算 列表and运算 > ...

  8. Python开发技术详解(视频+源码+文档)

    Python, 是一种面向对象.直译式计算机程序设计语言.Python语法简捷而清晰,具有丰富和强大的类库.它常被昵称为胶水语言,它能够很轻松的把用其他语言制作的各种模块(尤其是C/C++)轻松地联结 ...

  9. 【python进阶】详解元类及其应用2

    前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...

随机推荐

  1. 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 百篇博客分析OpenHarmony源码 | v28.03

    百篇博客系列篇.本篇为: v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当 ...

  2. VirtualBox上安装Debian10个人备忘笔记

    准备 VirtualBox 下载链接:Downloads – Oracle VM VirtualBox,下载完成后安装即可. Debian 下载链接:通过 HTTP/FTP 下载 Debian CD/ ...

  3. 深入思考软件工程,开启 DevOps 之旅

    20 世纪 60 年代,软件开始脱离硬件,逐渐成为一个独立产业.至今,软件开发过程从瀑布模型.CMM/CMMI,到 20 年前敏捷的诞生,再到今天 DevOps 的火热,一代代软件人在思考和探索,如何 ...

  4. Unity——AssetBundle打包工具

    Unity批量打AB包 为了资源热更新,Unity支持将所有资源打包成AssetBundle资源,存放在SteamingAssets文件夹中: 在项目发布之前,需要将所有资源打包成.ab文件,动态加载 ...

  5. 一个神秘的oj2587 你猜是不是dp(线段树优化建图)

    哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T, ...

  6. 哈工大知识图谱(Knowledge Graph)课程概述

    一.什么是知识图谱 知识(Knowledge)可以理解为 精炼的数据,知识图谱(Knowledge Graph)即是对知识的图形化表示,本质上是一种大规模语义网络 (semantic network) ...

  7. AES解密尾部出现乱码问题

    说明 在使用AES解密的时候我发现解密出来的字符串尾部一直都有乱码 解决方案 尾部字符串的ascii码就是删除位索引 具体代码: cryptor = AES.new('AES_KEY'.encode( ...

  8. 「软件测试实战教程系列(三)」弃繁就简,接口测试神器Postman|收藏版

    软件测试实战教程系列(三)弃繁就简,接口测试神器Postman|收藏版 Postman主要帮我们干了三件事: 1.把相关集合放到一个集合当中方便管理. 2.对指定接口发送请求. 3.断言 下面我们使用 ...

  9. 使用寄存器点亮LED

    1. 项目:使用stm32寄存器点亮LED, 分别点亮红.绿.蓝3个灯. 2. 代码: 只需要编写main.c程序,stm3210x.h程序为空(只需要新建即可). 2.1 点亮绿灯main.c程序 ...

  10. 脚本注入1(boolean&&get)

    现在,我们回到之前,练习脚本支持的布尔盲注(get型). 布尔盲注的应用场景是查询成功和失败时回显不同,且存在注入点的地方. 这里以Less-8为例: 发现查询成功时,会显示:失败则无回显. 同时发现 ...