Python小知识:推导式用法大全,Comprehension

推导式」的英文是「Comprehension」,是Python学习者引以为豪的一种写法。它的主要好处是「写起来简洁」,不用for循环,非常的「Pythonic」。

它包括「列表推导式」,「字典推导式」,「集合推导式」,还有「生成器推导式」等。推导过程可以使用「条件推导」,或者在推导表达式中应用「分支语句」,非常灵活。

本文核心内容之前发过,这次作为Python终结者系列重发一次,也做了一些补充。

熟练使用本文中的样例代码,就基本全面掌握了推导式的知识。建议把文中代码多练习几次。

1 基本推导式

写一段代码生成1到100之间的数字的平方的列表,答案是:

14916...

如果你这样写,你就不Pythonic了:

nums = []
for i in range(1,101):
    nums.append(i*i)
print(nums)

正确的写法是使用Python的推导式:

nums = [i*i for i in range(1,101)]

上面的推导式有3个关键点:

  • for循环」,其中包含被循环的range对象和代表当前变量的i
  • i * i 是推导「表达式」,表示根据for循环中的i推导出i * i
  • 整个表达式用「方括号」表示推导的结果生成一个列表

2 带条件的推导式

推导式也可以添加条件,这让推导式的应用更加广泛。

生成一个列表,包含1到100之间是3的倍数的数字的平方:

93681...

代码:

nums = [i*i for i in range(1,101) if i%3==0]

这样把推导式的3个要素变成了4个:

  • for循环
  • 表达式 i * i
  • 推导套件 if i % 3 == 0
  • 方括号

注意这些要素的顺序不能变化

3 在推导表达式中应用分支语句

推导式不光可以用if,还可以用else。

生成一个列表,如果是3的倍数就用平方,否则就用是数字本身:

1294536...

代码:

nums = [i*i if i%3==0 else i for i in range(1,101)]

注意带分支的情况下,if…else写在了for循环的左边,它的实际过程是:

  • 对整个range进行推导
  • 在推导过程中用if…else决定输入出什么

这和前面的if推导式是不同的

结合上面的3个例子,来看一下推导式总结:

1.推导式从一个可枚举数据(列表,元组,集合,字典等)推导出一个列表。也可以推导出生成器,集合或字典。

2.推导式可以加推导条件,只对符合条件的元素推导

3.要推导出的元素使用表达式生成,可以用if else生成不同元素

[表达式 if 表达式条件 else 分支 for i in 序列 if 推导条件]

4 在推导式中使用函数

如果推导条件或者表达式特别复杂怎么办?可以使用函数。

推导所有1-100之间的所有质数:2,3,5,7…

def is_prime(num):
    if num == 1:
        return False  
    for i in range(2,num):
       if (num % i) == 0:
           return False
    else:
       return True

p_nums = [i for i in range(1,100) if is_prime(i)]
print(p_nums)

把推导的条件放在函数中,既可以应对复杂的条件,又可以利用推导式的简洁写法。

同理,如果生成推导结果的过程很复杂,也可以把逻辑放到函数中。

推导1900到2021年之间所有的年份,标记出闰年,生成结果:

1900, 1901, 1902, 1903, '闰1904'

代码:

def is_run(year):
    if (year % 4) == 0:
       if (year % 100) == 0:
           if (year % 400) == 0:
               return True   # 整百年能被400整除的是闰年
           else:
               return False
       else:
           return True       # 非整百年能被4整除的为闰年
    else:
       return False 

ryears = [f'闰{y}' if is_run(y) else y for y in range(1900, 2021)]    
print(ryears)

5 推导式中嵌套推导式

从2000年到2021年,生成每个月份:‘2000年:1月’, ‘2000年:2月’, ‘2020年:3月’, …, ‘2021年:12月’

monthes = [f'{y}年:{m}月' for y in range(2000, 2022) for m in range(1,13) ]

这里有两个for循环,类似于:

monthes = []
for y in range(2000, 2022):
    for m in range(1,13):
        monthes.append(f'{y}年:{m}月')

是不是下面的特别容易懂?所以两层的循环不推荐使用推导式,哈哈。

那我为什么还要讲?你会碰到有人这么写,知道它的存在还是有点必要的。

6 推导巨大的列表 - 不要这么干!

推导出1到100亿之间的数字的平方,代码如下:

nums = [i*i for i in range(1,10000000000)]

但是这段代码很可能会卡死你的电脑,除非你的电脑是超级计算机。因为它要在内存中做100亿次计算,然后保存这100亿个数字。

正确的做法是使用生成器推导式。

7 生成器推导式

这种情况下,我们应该使用推导生成器,用法很简单:

  • 把方括号改成圆括号就可以了
nums = (i*i for i in range(1,10000000000))
print(nums)
print(next(nums))
print(next(nums))
print(next(nums))

打印出来是一个生成器:

<generator object <genexpr> at 0x7fa0b422feb0>
1
4
9

这是一个生成器,它不会一次性生成100亿个数字,只有调用next()的时候,它才会生成一个新的,返回给你。也就是说,同一个时间,只保存一个数字。

生成器的内容请关注本公众号,下一期的终结者系列:生成器。

8 字典推导式

除了推导列表,生成器,还可以推导字典。

推导字典的方式和推导列表很相似,只不过:

1.使用大括号

2.使用键值对

推导一个包含数字和数字平方组成的字典,结果是这样的:

{1: 1, 2: 4, 3: 9, ..., 100: 10000}

代码:

nums_dict = {n:n*n for n in range(1,101)}
print(nums_dict)

反过来,平方在前面,数字在后面:

nums_dict = {n*n:n for n in range(1,101)}
print(nums_dict)

给下面的字典按照分数排序:

{'叔':59, '张三':87, 'FGA':78, '石石':100, '莫名':90}

排序结果:

{'石石': 100, '莫名': 90, '张三': 87, 'FGA': 78, '叔': 59}

代码:

scores = {'叔':59, '张三':87, 'FGA':78, '石石':100, '莫名':90}
sored_scores = {item[0]:item[1] for item in sorted(scores.items(), key=lambda item:item[1], reverse=True)}
print(sored_scores)

1.先把字典scores变成一个元组列表:「scores.items()」

2.用sorted函数给元组列表排序:「sorted(scores.items(), key=lambda item:item[1], reverse=True)

3.排序过程用lambda指定使用元组的第二列排序:「key=lambda item:item[1]」。默认是是第一列。

4.指定倒着排序,也就是分数高的在前面:reverse=True

5.使用推导式,把排好序的元组列表,生成一个新的排好序的字典:「{item[0]:item[1] for item in … }

9 集合推导式

推导集合的方式和列表是一样的,区别在于:

1.使用大括号,类似于推导字典,但它是单个元素,而不是键值对。

2.集合会自动过滤掉重复的元素。

下面的名字列表,去掉前后空格后去掉重复的名字:

[ '叔', '张三', ' 麦叔 ', 'FGA ', '张小三', 'FGA', '石石',' 莫名','莫名' ]

推导结果:

{'石石', 'FGA', '张小三', '莫名', '张三', '叔'}

代码:

names = [ '叔', '张三', ' 麦叔 ', 'FGA ', '张小三', 'FGA', '石石',' 莫名','莫名' ]
new_names = {n.strip() for n in names}
print(new_names)

推荐阅读

睡在我上铺的室友用python,一个月挣了我一学期的生活费

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值