展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Python列表解析和生成器表达式的结构是什么?

Python列表解析和生成器表达式的结构是什么?

列表解析与生成器表达式生成器表达式是生成容器的一种简洁方式。最常见的是,你会听到列表解析,但也存在集合解析和字典解析。但是,术语上的差异有些重要:如果你实际上是在制作列表,那么它只是一个列表解析。生成器表达式用括号括起来(),而列表解析用方括号括起来[]。集合解析用花括号括起来{}。除了这些差异之外,所有三种情况的语法都是相同的!(字典解析还有更多内容,我们稍后会讨论。)生成器表达式与生成器有关,我们将在后面的部分深入探讨。现在,我们只要使用生成器表达式的官方定义就足够了:生成器表达式-返回迭代器的表达式

本文目录

    列表解析与生成器表达式

    生成器表达式是生成容器的一种简洁方式。最常见的是,你会听到列表解析,但也存在集合解析和字典解析。但是,术语上的差异有些重要:如果你实际上是在制作列表,那么它只是一个列表解析。

    生成器表达式用括号括起来( ),而列表解析用方括号括起来[ ]。集合解析用花括号括起来{ }。除了这些差异之外,所有三种情况的语法都是相同的!

    (字典解析还有更多内容,我们稍后会讨论。)

    生成器表达式与生成器有关,我们将在后面的部分深入探讨。现在,我们只要使用生成器表达式的官方定义就足够了:

    生成器表达式 - 返回迭代器的表达式。

    生成器表达式的结构

    生成器表达式(或列表/集合户外组)有点像一个被翻转的for循环。

    举一个简单的例子,让我们回顾上一篇文章中的一个例子,我们将华氏温度列表转换为摄氏温度。我会稍微调整一下,所以数字将存储在另一个列表中,而不是直接打印。

    temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]
    temps_c = []
    
    def f_to_c(temp):
        return round((temp - 32) / 1.8, 1)
    
    for c in map(f_to_c, temps_f):
        temps_c.append(c)
    
    print(temps_c)

    信不信由你,列表解析将使整个程序减少到三行!我们一次简化为一部分,好让你可以理解我的意思。

    让我们从用列表解析替换 for 循环开始......

    temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]
    
    def f_to_c(temp):
        return round((temp - 32) / 1.8, 1)
    
    temps_c = [f_to_c(temp) for temp in temps_f]
    
    print(temps_c)

    重要的代码行是temps_c = [f_to_c(temp) for temp in temps_f]. 这表现得非常像map()。temp对于列表中的每个元素temps_f,我们应用该函数f_to_c()。

    现在,如果我在其他地方需要f_to_c()函数,我就停在这里结束了。但是,如果这是我需要华氏到摄氏度转换逻辑的唯一地方,我可以完全不使用该函数,并将逻辑代码直接移动到解析中:

    temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]
    temps_c = [round((temp-32) / 1.8, 1) for temp in temps_f]
    print(temps_c)

    我跟你说了什么?三行!是不是只有三行代码!

    根据我获得的数据,我甚至可以进一步减少。让我们用另一个例子来看看这个。

    想象一下,你有一个程序在一行上接收一堆整数,用空格分隔,例如5 4 1 9 5 7 5。 你想找到所有这些整数的总和。(为简单起见,假设你没有输入错误的风险。)

    让我们先以一种显而易见的方式编写它,而无需列表解析。

    user_input = input()
    values = user_input.split(' ')
    
    total = 0
    
    for v in values:
        n = int(v)
        total += n
    
    print(total)

    很明显,对吧?我们将用户输入作为字符串获取,然后将该字符串以空格拆分列表以获取各个数字。我们创建一个变量来存储总数,然后使用循环遍历每个值,将其转换为整数,然后将其添加到总数中。现在我们有了代码逻辑,让我们对其进行简化和优化。

    让我们首先在这里简化一些显而易见的代码。我们之前已经介绍了所有这些概念,所以看看你是否能发现我改进的地方。

    values = input().split(' ')
    total = 0
    
    for v in values:
        total += int(v)
    
    print(total)

    除非我们使用列表解析,否则我们不能比这更简单,所以现在就开始吧!

    values = input().split(' ')
    total = sum(int(v) for v in values)
    print(total)

    这里的生成器表达式是(int(v) for v in values)。v对应列表中的每个值values,我们将其转换为整数 ( int(v))。

    请注意我是如何使用该sum()函数的,将生成器表达式直接传递给它。由于表达式直接作为唯一参数传递,因此我不需要在它周围加上额外的括号。

    现在,如果我不需要values其他任何列表,我实际上可以将该逻辑直接移动到生成器表达式中!

    total = sum(int(v) for v in input().split(' '))
    print(total)

    像做馅饼一样容易,对吧?

    嵌套列表解析

    如果相反,我们想要输入的每个数字的平方和呢?事实上,有两种方法可以做到这一点。简单做法是这样:

    total = sum(int(v)**int(v) for v in input().split(' '))
    print(total)

    这行得通,但不知何故,它只是感觉不对,不是吗?我们要转换两次v为整数。

    我们可以通过将列表解析嵌套到我们的生成器表达式中来解决这个问题!

    total = sum(n**2 for n in [int(v) for v in input().split(' ')])

    列表解析和生成器表达式从内部到外部进行解析。最里面的表达式 ,int(v) for v in input().split(' ')首先运行,并且封闭的方括号[ ]将其转换为列表(可迭代)。

    接下来,n**2 for n in [LIST]运行外部表达式,[LIST]就是我们刚才生成的列表。

    这种嵌套不是很容易理解,也不直观。尽量少用它。当我需要嵌套时,我将每个列表理解写在单独的行上并将其存储...

    the_list = [int(v) for v in input().split(' ')]
    total = sum(n**2 for n in the_list)
    print(total)

    ...测试一下,然后通过复制和粘贴开始嵌套。

    生成器表达式中的条件

    如果我们只想要列表中奇数的总和怎么办?生成器表达式和列表解析也可以做到这一点。

    我们将在此示例中使用嵌套,但我们将首先从非嵌套版本开始,为了使新逻辑更易于查看。

    the_list = [int(v) for v in input().split(' ')]
    total = sum(n**2 for n in the_list if n%2==0)
    print(total)

    新部分在第二行。在生成器表达式的末尾,我添加了if n%2==0. 你可能认识模运算符 ( %),它为我们提供了除法的余数。任何偶数都可以被2整除,这意味着它没有余数。因此,n%2==0仅适用于偶数。

    将条件放在语句之后而不是之前,感觉有点奇怪。理解它的最简单方法是和没有生成器表达式的相同代码逻辑做对比......

    output = []
    for n in the_list:
        if n%2==0:
            output.append(n**2)

    基本上,要将其转换为生成器表达式,你只需知道append(),从这儿开始......

    n**2
    for n in the_list:
        if n%2==0:

    然后从for和if语句中删除冒号 ( :)、换行符缩进...

    n**2 for n in the_list if n%2==0

    多个迭代对象

    我们还可以使用生成器表达式和列表解析一次循环遍历多个可迭代对象,其方式与嵌套循环相同。

    考虑以下逻辑:

    num_a = [1, 2, 3, 4, 5]
    num_b = [6, 7, 8, 9, 10]
    output = []
    
    for a in num_a:
        for b in num_b:
            output.append(a*b)

    我们也可以按照我刚才给出的相同步骤将其转换为列表解析!我们把append()的参数放在前面...

    a*b
    for a in num_a:
        for b in num_b:

    ...然后我们将其余部分折叠成一行,删除冒号。

    a*b for a in num_a for b in num_b

    最后,将其包裹在方括号中,并将其复制给变量output输出。

    output = [a*b for a in num_a for b in num_b]

    集合解析

    正如我在文章开头提到的,就像你可以使用包含在方括号[ ]中的生成器表达式来创建列表一样,你也可以使用花括号{ }来创建集合。

    例如,让我们生成通过100 除以小于 100 的奇数得到的所有余数组成的集合。通过使用集合,我们确保没有重复项,使结果更容易理解。

    odd_remainders = {100%n for n in range(1,100,2)}
    print(odd_remainders)

    运行该代码给我们...

    {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49}

    这里真的没有什么特别的地方。集合解析的工作方式与列表解析相同,只是创建了不同的容器。

    字典解析

    字典解析遵循与其他形式的生成器表达式几乎相同的结构,但有一个区别:冒号。

    如果你还记得,当你创建集合或字典时,你使用花括号{ }。唯一的区别是,在字典中,你使用冒号:来分隔键值对,这是在集合中不会执行的操作。同样的原则在这里也适用。

    例如,如果我们想创建一个字典,将 1 到 100 之间的整数存储为键,并将该数字的平方作为值...

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

    这就是字典解析!除了冒号之外:,其他所有内容都与任何其他生成器表达式相同。

    风险

    对所有情况都使用列表解析或生成器表达式可能非常诱人。它们相当容易上瘾,部分原因是写出来时看起来非常高端优雅。强大的单行代码让程序员非常兴奋——我们真的很喜欢优雅地地处理我们的代码。

    但是,我必须提醒你不要过分追求优雅。记住The Zend Of Python,这里有一些与此主题相关的部分:

    美丽总比丑陋好。
    ...
    简单胜于复杂。
    复杂胜于复杂。
    平面优于嵌套。
    稀疏比密集好。
    可读性很重要。
    ...

    列表解析可能很优雅,但如果使用不当,它们也可能成为密集的、垃圾的逻辑片段。

    1.代码变得难以阅读

    我从互联网上的一项调查中借用了这个例子

    primary = [ c for m in status['members'] if m['stateStr'] == 'PRIMARY' for c in rs_config['members'] if m['name'] == c['host'] ]
    secondary = [ c for m in status['members'] if m['stateStr'] == 'SECONDARY' for c in rs_config['members'] if m['name'] == c['host'] ]
    hidden = [ m for m in rs_config['members'] if m['hidden'] ]

    你能说出这段代码的意思?如果你阅读一会,你可能可以,但你为什么要阅读?代码一清二楚。(在调查中,这被评为最不可读的示例。)当然,你可以添加注释来解释正在执行的逻辑 - 事实上,他们在原始示例中做了 - 但任何时候你需要注释来解释代码正在做什么,这几乎可以肯定太复杂了。

    列表解析和生成器表达式固然很强大,但如果大量使用会像刚刚那样变得难以阅读。

    不一定非得像刚刚那样做。只需将列表理解拆分为多行,你就可以重新获得很多可读性,其结构与传统循环类似。

    primary = [
        c
        for m in status['members']
            if m['stateStr'] == 'PRIMARY'
        for c in rs_config['members']
            if m['name'] == c['host']
        ]
    
    secondary = [
        c
        for m in status['members']
            if m['stateStr'] == 'SECONDARY'
        for c in rs_config['members']
            if m['name'] == c['host']
        ]
    
    hidden = [
        m
        for m in rs_config['members']
            if m['hidden']
        ]

    请注意,这并不能完全证明上述说法是正确的。我仍然会使用传统的循环而不是前面的示例,只是因为它们更易于阅读和维护。

    如果你仍然不相信这是 Python 的一个容易被滥用的特性?我的有一个朋友分享他遇到的这个真实案例。我们根本不知道它做了什么。

    cropids = [self.roidb[inds[i]]['chip_order'][
                   self.crop_idx[inds[i]] % len(self.roidb[inds[i]]['chip_order'])] for i in
               range(cur_from, cur_to)]

    光是看着,我的可能都会有点烦躁了。

    2.它们不会替换循环

    看看以下情况。(此代码是虚构的,仅供参考。)

    some_list = getTheDataFromWhereever()
    [API.download().process(foo) for foo in some_list]

    对于未经训练的人来说,这看起来没啥问题,但请注意请仔细看砍......数据some_list正在被直接修改(变异),但结果没有被存储。这是列表解析甚至生成器表达式被滥用来代替循环的情况。它使阅读变得困难,更不用说调试了。

    无论你想使用生成器表达式来变得优雅,这都是你应该坚持使用循环的一种情况:

    some_list = getTheDataFromWhereever()
    for foo in some_list:
        API.download().process(foo)

    3.它们很难调试

    想一想列表解析的本质:你将所有内容打包成一个巨大的语句。这样做的好处是你消除了一堆中间步骤。缺点也是……你消除了一堆中间步骤。

    考虑调试一个典型的循环。你可以单步执行它,一次迭代,使用调试器随时观察每个变量的状态。你还可以使用错误处理来处理异常的边缘情况。

    相比之下,这些都不适用于生成器表达式或列表解析。一切要么有效,要么无效!你可以尝试解析错误和输出以找出你做错了什么,但我可以向你保证,这是一种令人困惑的体验。

    你可以通过避免在你的第一个代码版本中使用列表解析来避免这种疯狂!使用传统的循环和迭代器工具以显而易见的方式编写逻辑。一旦你知道它有效,那么并且只有在那时你才应该将逻辑折叠到生成器表达式中,并且只有在你可以这样做而不避免错误处理的情况下。

    这听起来像是很多额外的工作,但我在平常的代码编写中中遵循了这个确切的模式。我对生成器表达式的理解通常是我对抗经验不足的竞争对手的主要优势,但我总是先编写标准循环:我不能把浪费时间在调试生成器表达式中错误逻辑上。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。