资讯专栏INFORMATION COLUMN

Python 进阶之路 (八) 最用心的推导式详解 (附简单实战及源码)

hufeng / 1028人阅读

摘要:什么是推导式大家好,今天为大家带来问我最喜欢的推导式使用指南,让我们先来看看定义推导式是的一种独有特性,推导式是可以从一个数据序列构建另一个新的数据序列的结构体。

什么是推导式

大家好,今天为大家带来问我最喜欢的Python推导式使用指南,让我们先来看看定义~

推导式(comprehensions)是Python的一种独有特性,推导式是可以从一个数据序列构建另一个新的数据序列的结构体。一般有三种使用最多的推导式:

列表推导式(list comprehensions)

字典推导式(dict comprehensions)

集合推导式(set comprehensions)

使用推导式可以简化代码的同时提高效率,在我的个人使用场景中,用的最多的还是列表推导式,接下来我会一一介绍这三种常见的推导式,最后通过一个简单实战发现推导式的高效之处

列表推导式(list comprehensions)
模板

首先,让我们看看使用列表推导式的基础模板:

[ expression for item in list if conditional ]

简单来说,遍历一个list,得到每一个元素item,我们相对item进行哪些操作,写在expression里就可以,如果对筛选有什么条件,可以放在if后面

下面可以通过大量实例帮助大家理解

使用实例

先看第一个小栗子,在这里我们用for循环常规遍历一个字符串‘human’,把每一字母作为元素放在一个叫h_letters的数组里面:

h_letters = []
for letter in "human":
    h_letters.append(letter)

print(h_letters)

Out:["h", "u", "m", "a", "n"]

如果我们根据列表推导式的定义模板,可以简化如下:

h_letters = [ letter for letter in "human" ]
print( h_letters)

Out: ["h", "u", "m", "a", "n"]

这样的话便捷了很多,看上去也很容易理解,这里我们在expression部分什么都没有写,只是提出了每个元素而已,运行时的python执行方式如下:

我们可以在expression的部分进行很多操作,比如:

h_letters = [ letter.upper() for letter in "human" ]
print( h_letters)

Out: ["H", "U", "M", "A", "N"]

这样我们可以很容易的实现字母的大小写转化

同样的,我们可以在if后面写出筛选条件,比如这里,我们想要提出从-20 ~ 20中所有能被3整除的正数:

result = [num for num in range(-20,20)        
          if num %3==0 and num > 0]   

print(result)                   #多个条件可以用and连接

Out: [3, 6, 9, 12, 15, 18]

列表推导式的实际应用场景十分广泛,它和lambda不同,是真正好理解,提高效率的python特性之一,这里相信聪明的你已经想到了更多用法!

字典推导式(dict comprehensions)
模板

让我们看先来看使用字典推导式的基础模板:

{ key:value for key,value in existing_data_structure }

这里和list有所不同,因位dict里面有两个关键的属性,key 和 value,但大同小异,我们现在的expression部分可以同时对 key 和 value 进行操作

下面来看最常见的应用

使用实例

首先最实用的功能莫过于可以实现一个dict的key,value值互换:

person = {"name":"xiaobai","city":"paris"}
person_reverse = {v:k for k,v in person.items()}   #简单互换key和value的值即可

print(person_reverse)
Out: {"xiaobai": "name", "paris": "city"}

这里就非常方便了用字典推导式,不然的话如果用for循环,会稍微麻烦一些。
让我们再看下一个很巧的例子:

nums = {"a":10,"b":20,"A":5,"B":3,"d":4}

num_frequency  = {k.lower():nums.get(k.lower(),0) + nums.get(k.upper(),0)
                  for k in nums.keys() }

print(num_frequency)

Out: {"a": 15, "b": 23, "d": 4}

这里使用的就比较灵活,我们有一个数据,key是字母的大小写混在一起,我们想统计同一个key(大小写都包括)所对应的数字出现总和,所以在新建的num_frequency 字典用使用了推导式,这里我们遍历的是dict.keys()配合dict.get()方法,当然,如果仅仅是为了实现这个功能,我们有更好的办法,这里只是为了介绍推导式

再比如下面的例子:

fruit = ["apple","banana","organge","mango","peach"]

fruit_len = {f:len(f) for f in fruit}
print(fruit_len)

Out:{"apple": 5, "banana": 6, "organge": 7, "mango": 5, "peach": 5}

我们有一个fruit的list,现在想要得到每一种水果的单词长度,就可以通过图中所示的方法实现,非常容易

最后再来看一个字典推导式配合枚举(enumerate)的例子:

fruit = ["apple","organge","banana","mango","peach"]

fruit_positon = {v:i for i,v in enumerate(fruit)}
print(fruit_positon)

Out: {"apple": 0, "organge": 1, "banana": 2, "mango": 3, "peach": 4}

还是用刚才的list,这次我们得到的key是fruit的每个元素,value则是该元素在fruit所在的index

集合推导式(Set comprehensions)
模板

让我们看先来看使用集合推导式的基础模板:

{ expression for item in Sequence if conditional }

其实集合推导式和list的推导式很像,但是既然是集合,肯定会配合利用Set的特有属性来实现我们的目的,如果你还对Set这种数据结构不够了解,可以参考我之前的文章:Python 进阶之路 (四) 先立Flag, 社区最全的Set用法集锦

下面来看最常见的应用

使用实例

首先,我们来看一个根据Set值唯一的特性的例子,我们有一个list叫names,用来存储名字,其中的数据很不规范,有大写,小写,还有重复的,我们想要去重并把名字的格式统一为首字母大写,实现方法便是用Set推导式:

names = [ "Bob", "JOHN", "alice", "bob", "ALICE", "James", "Bob","JAMES","jAMeS" ]
names_standard = { n[0].upper()+n[1:].lower() for n in names}

print(names_standard)
Out: {"John", "Bob", "James", "Alice"}

这里就不再举很多的其他例子了,因为使用的方式多种多样,剩下的就靠广大人民群众的智慧自行开发即可!

简单实战

现在让我们来看一个比较综合的例子!我们现在手里有一个英文字典的dictionary.txt文件,包含从A~Z的单词

具体需求:我们想要找到长度大于5的正反拼写都具有实际含义的单词

我们现在会通过各种推导式来实现这个目标,我会在文章最后把txt文件及Python文件下载链接附上,这样大家如果先要练习可以自行下载

首先,我们的初始目录结构如下:

这里我新建了一个test文件夹,把dictionary.txt 文件和python文件放在一起方便读取,开始之前,先大概看下txt文件长什么样子:

第一步:读取dictionary.txt中的单词,选出长度大于5的
with open("dictionary.txt") as dictionary_file:
    words = (line.rstrip() for line in dictionary_file)
    words_over_five_letters = [w for w in words if len(w)>5 ]
    

这里通过列表推导式words_over_five_letters 用来存储所有长度大于5的单词

第二步:将上一步选出的单词全部以倒序的方式存储在一个集合里
reversed_words ={
    word[::-1]
    for word in words_over_five_letters
    }

通过set推导式来实现

第三步:通过 if 条件筛选得出结果
reversible_words = [
    word
    for word in words_over_five_letters
    if word in reversed_words
]

for word in reversible_words[0:20]:
    print(word)
    
    
Out:
    abrood
    agenes
    amaroid
    amunam
    animal
    animes
    bruted
    darter
    decart
    decurt
    deedeed
    deflow
    degami
    degener
    degged
    deified
    deifier
    deliver
    denier

这里最后共有203个结果,我们只看了前20个,验证方法就是只要长度大于5的单词同时存在于reversed_words和words_over_five_letters即可

完整代码如下:

with open("dictionary.txt") as dictionary_file:
    words = (line.rstrip() for line in dictionary_file)
    words_over_five_letters = [w for w in words if len(w)>5 ]


reversed_words ={
    word[::-1]
    for word in words_over_five_letters
     }

reversible_words = [
    word
    for word in words_over_five_letters
    if word in reversed_words
]

for word in reversible_words[0:20]:
    print(word)
资料下载

dictionary.txt

dictionary.py

总结

这次为大家总结了python里面常见的三种推导式相关用法以及最后的小实战环节,希望大家喜欢,双击666点个赞吧!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/43214.html

相关文章

  • Java学习路线总结,搬砖工逆袭Java架构师(全网强)

    摘要:哪吒社区技能树打卡打卡贴函数式接口简介领域优质创作者哪吒公众号作者架构师奋斗者扫描主页左侧二维码,加入群聊,一起学习一起进步欢迎点赞收藏留言前情提要无意间听到领导们的谈话,现在公司的现状是码农太多,但能独立带队的人太少,简而言之,不缺干 ? 哪吒社区Java技能树打卡 【打卡贴 day2...

    Scorpion 评论0 收藏0
  • Python 进阶之路 (二) Dict 进阶宝典,初二快乐!

    摘要:新年快乐大家好,今天是大年初二,身在国外没有过年的氛围,只能踏实写写文章,对社区做点贡献,在此祝大家新年快乐上一期为大家梳理了一些的进阶用法,今天我们来看字典的相关技巧,我个人在编程中对字典的使用非常频繁,其实对于不是非常大的数据存储需求, 新年快乐 大家好,今天是大年初二,身在国外没有过年的氛围,只能踏实写写文章,对社区做点贡献,在此祝大家新年快乐!上一期为大家梳理了一些List的进...

    ChristmasBoy 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    spacewander 评论0 收藏0
  • 后台开发常问面试题集锦(问题搬运工,链接)

    摘要:基础问题的的性能及原理之区别详解备忘笔记深入理解流水线抽象关键字修饰符知识点总结必看篇中的关键字解析回调机制解读抽象类与三大特征时间和时间戳的相互转换为什么要使用内部类对象锁和类锁的区别,,优缺点及比较提高篇八详解内部类单例模式和 Java基础问题 String的+的性能及原理 java之yield(),sleep(),wait()区别详解-备忘笔记 深入理解Java Stream流水...

    xfee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<