在不讨论 lambda 表达式的情况下, 我很难深入地讲授 Python 类. 我经常遇到有关它们的问题. 学生们往往会在 StackOverflow 或者他们同事的代码中(实际上, 这个也可能来自StackOverflow)碰到他们.
我对 lambda 有很多的疑问, 我很犹豫是否要推荐学生接受 Python lambda 表达式. 多年来我一直都很厌恶 lambda 表达式, 自从几年前我开始频繁教授 Python 后, 我对它的厌恶与日俱增.
我将会说明我对 lambda 表达式的看法, 以及为何我倾向于建议学生们避免使用它.
更多Python视频、源码、资料加群683380553免费获取
Python 中的 lambda 表达式: 它们是什么?
lambda 表达式是 Python 中创建匿名函数的一个特殊语法. 我称 lambda 语法本身为 lambda 表达式, 而它返回的函数我称之为 lambda 函数.
Python 的 lambda 表达式允许在一行代码中创建一个函数并传递(通常传递到另外一个函数).
lambda 表达式允许我们使用此代码:
并将其转换为以下代码:
lambda 表达式仅仅是创建函数的一个特殊方法. 它们只包含一条语句, 并自动返回这条语句的结果.
lambda 表达式本身的局限性实际上是其吸引力的一部分. 当经验丰富的 Python 程序员看到一个lambda 表达式时, 他们知道他们正在使用一个仅在一个地方有效的函数, 并且只做一件事情.
如果你曾经在 JavaScript 中使用过匿名函数, 那么Python 中的 lambda 表达式与之相同, 除了具有更多限制以及与传统函数完全不同的语法.
通常使用的地方
你通常会在调用接受函数作为参数的函数(或类)时, 使用 lambda 表达式.
Python 内置的 sorted 函数接受一个函数作为它的 key 参数. 这个 key 函数用于在决定条目排序顺序时计算比较键的值.
所以 sorted 可以作为一个经常使用 lambda 表达式范例:
上述代码返回了对给定颜色以不区分大小写方式排序的结果.
sorted 函数并不是 lambda 表达式的唯一用法, 但却是最普遍的一个.
lambda 的利弊
围绕 lambda 表达式和 def 定义的函数之间的一系列对比, 我发表一下看法. 这两类工具都可以提供函数, 但它们都有各自的限制, 使用了不同的语法.
lambda 表达式与 def 的主要不同点:
- 可以立刻传递(无需变量)
- 在内部只能包含一行代码
- 自动返回结果
- 既没有文档字符串, 也没有名称
- 使用了不同且不常见的语法
事实上, lambda 表达式能够被传递是它们最大的优势. 自动返回结果很简洁, 但在我看来并不是很大的优势. "单行代码"的限制总体上不好不坏. 而 lambda 函数没有文档字符串和名称令人遗憾, 而它们的一些不常见的语法可能会对新的Pythonista造成困扰.
总的来说, 我觉得 lambda 表达式的缺点略微超过了它的优点, 但我对它们最大的怨念是它们往往被滥用或者过度使用.
lambda 被滥用和过度使用
当我在陌生代码中看到 lambda 表达式时, 我立刻会新生疑虑. 当我在自然环境下遇到 lambda 表达式时, 我经常发现去掉它们之后能提高代码的稳定性.
有时候 lambda 表达式会被滥用, 意味着它们的使用方式通常不理想. 另外有时候 lambda 表达式仅仅被过度使用, 意味着它们可以被接受, 但我个人更愿意看到以其他不同方式编写的代码.
让我们来看一下 lambda 表达式被滥用和过度使用的几种方式.
滥用: 命名 lambda 表达式
官方 Python 风格指南 PEP8 建议永远不要编写这样的代码:
上述语句创建了一个匿名函数并赋值到一个变量. 上面的代码忽视了用 lambda 的原因: lambda 函数可以被直接传递而无需先赋值给一个变量.
如果你想创建一个一行代码的函数并存储到变量中, 你应该使用def:
PEP8 推荐这种方式, 因为命名函数是一个常见并容易理解的东西. 同时给函数一个合适的名称也是很有好处的, 可以让调试简单一些. 而与 def 定义的函数不同, lambda 函数从来都没有一个名称(名称都是<lambda>):
如果你想创建一个函数并存储到变量中, 请使用 def 来定义. 这正是它的用途. 无论你的函数是一行代码还是在另外一个函数中定义, 都可以, def 正适合这些应用场景.
滥用: 调用不必要的函数
我经常看到用 lambda 表达式封装一个已经很适合当前问题的函数.
例如这段代码:
写这段代码的人很可能了解过, 知道 lambda 表达式是用来创建一个可传递函数的. 但他们却忽略了一个更大一些的理念: Python 中所有的函数(不止 lambda 函数)都是可传递的.
既然 abs(返回一个数字的绝对值) 是一个函数并且所有函数都是可传递的, 实际上我们可以将上述代码编写为:
这个例子可能会让人感到有些假, 但以这种方式来使用 lambda 表达式并不十分罕见. 这是我看到的另外一个例子:
因为我们接受与我们传给 min 完全相同的参数, 所以完全没有必要调用额外的函数. 我们可以直接将 min 函数传递给 key:
如果你已经有了另一个符合你要求的函数, 则不需要一个 lambda 函数.
过度使用: 简单, 但不常用的函数
lambda 表达式通常用于创建一个在元组中返回一系列值的函数.
这里的 key 所传的函数让我们可以根据长度以及大小写标准化的名称来对颜色进行排序.
下面的代码与上面的功能相同, 但我认为更有可读性:
代码看上去有点啰嗦, 但我觉得 key 函数的名称可以让排序的依据更加清晰. 我们不是只依据长度排序, 也不是只依据颜色排序: 我们同时使用了两者.
如果一个函数很重要, 那么它应当有一个名称. 你可以争论说, lambda 表达式中使用的大多数函数都不重要, 不值得给一个名称, 但命名函数通常没什么缺点, 而且我发现它通常会使我的代码整体上可读性更好.
给函数命名通常会让代码更有可读性, 同样的, 使用元组拆包来命名变量而不是使用随机索引查找的方式通常会让代码更有可读性.
过度使用: 多行代码有帮助的时候
有时候 lambda 表达式"只有一行"这方面的特性会导致我们用复杂的方式来编写代码. 例如下面的例子:
在这里我们对索引查找做了硬编码以按照颜色来对点进行排序. 如果我们使用一个命名函数, 我们可以用元组拆包来让代码更有可读性:
比起使用硬编码索引查找,元组拆包可以提升可读性. 使用 lambda 表达式通常意味着牺牲掉一些 Python 语言的特性, 尤其是需要多行代码的时候(比如额外的赋值语句).
过度使用: lambda 与 map 和 filter
Python 的 map 和 filter 函数经常与 lambda 表达式搭配在一起使用. 当在 StackOverflow 上提问"什么是 lambda 表达式"的问题时, 经常会看到以下例子中的代码:
Python 的 map 和 filter 函数用来循环并创建一个新的可迭代对象, 循环期间对每个元素做一些细微修改或者根据匹配的条件过滤到只剩一些元素. 我们完全可以只使用列表推导和生成器表达式来完成这两项任务:
滥用: 有时你甚至不需要去传递一个函数
那需要传递并执行单个操作函数的情况该怎么办?
热衷于函数式编程的新 Pythonistas 有时会写如下的代码:
上述代码对 numbers 列表中的所有数字做了加法. 但还有一个更好的方式来做这个操作:
Python 内置的 sum 函数就是专门做这个任务的.
sum 函数以及其他的一些专门的 Python 工具很容易被忽视. 但我建议你在需要时寻找更专业的工具, 因为它们通常会让代码更有可读性.
与其传递一个函数到其他函数中, **不如观察一下是否有更专业的方式来解决你的问题. **
过度使用: 使用 lambda 进行非常简单的操作
我们不说加法了, 再来说一下乘法吧:
上面的 lambda 表达式是很有必要的, 因为不允许我们传递 * 运算符, 就算它像一个函数一样. 如果有一个等价于 * 的函数, 我们就可以将它传递给 reduce 函数.
Python 的标准库实际上有一个完整的模块来解决这个问题:
Python 的运算符模块让 Python 的各种运算符像函数一样易用. 如果你正在练习函数式编程, Python 的 operator 模块就是你的好助手.
除了提供与 Python 许多运算符相对应的函数以外, operator 模块还提供了一系列常用的更高级的函数来访问条目和属性, 以及调用方法.
itemgetter 用来访问列表/序列的索引或字典/映射的键值:
attrgetter 用来访问对象的属性:
methodcaller 用来调用对象的方法:
我通常发现使用 operator 模块中的函数会使代码看上去比使用等效的 lambda 表达式更加清晰易懂.
过度使用: 当给高阶函数增加困惑时
一个接收其他函数作为参数的函数被称为高阶函数. 高阶函数通常就是我们经常向其传递 lambda 函数的那一类函数.
在练习函数式编程时高阶函数是很常用的. 然而函数式编程并不是应用 Python 思想的唯一方式: Python 是一种多范式语言, 因此我们可以混合并匹配编码规则, 让我们的代码更有可读性.
对比这个:
和这个:
第二段代码长一些, 但是没有函数式编程背景的人通常会觉得它更容易理解.
很多 Python 程序员来说, reduce/lambda 的组合可能都会有些晦涩难懂.
通常, 将一个函数传递给另一个函数会使代码更加复杂, 这不利于代码的可读性.
你应该使用 lambda 表达式吗?
基于以下原因, 我觉得 lambda 表达式的应用是有问题的:
- 对很多 Python 程序员来说, lambda 表达式是一种古怪而又陌生的语法
- lambda 函数本身缺少名称和文档, 意味着了解它们功能的唯一方式就是读代码
- lambda 表达式只能包含一条语句, 因此某些提高可读性的语言功能, 如元组拆包, 不能与它们一起使用
- lambda 函数通常可以被替换为标准库中已存在的函数或 Python 内置的函数
比起一个命名良好的函数, lambda 表达式缺乏即刻可读性. 尽管 def 语句通常更容易理解, 但 Python 还有很多可用于替换 lambda 表达式的功能, 包括特殊语法(推导), 内置函数(sum)和标准库函数(在 operator 模块中)
只有当你的情况完全满足这四个标准时, 我才会说你可以使用 lambda 表达式:
- 你所要做的操作是不重要的: 函数不值得一个名称
- 使用 lambda 表达式比你所能想到的函数名称让代码更容易理解
- 你很确定还没有一个函数能满足你的需求
- 你团队的每个人都了解 lambda 表达式, 并且都同意使用它们
如果上述四条中的任何一条都不符合你的情况, 我建议用 def 来写一个新的函数, (如果可能)接受一个在 Python 中已经存在且能满足你需求的函数.
来自 <https://blog.csdn.net/sinat_38682860/article/details/83933866>
相关推荐
内容概要:本文详细介绍了基于TMS320F系列芯片的C2000串口读写方案及其编程器——FlashPro2000的功能特点和支持的接口模式。文中不仅涵盖了硬件连接的具体步骤,还提供了代码实例来展示Flash擦除操作,并对比了JTAG和SCI-BOOT两种模式的优缺点。此外,针对不同型号的C2000系列芯片,给出了详细的适配指导以及避免烧录过程中可能出现的问题的方法。 适合人群:从事DSP开发的技术人员,尤其是对TI公司C2000系列芯片有一定了解并希望深入了解其编程和烧录细节的人群。 使用场景及目标:适用于实验室环境下的程序调试阶段,以及生产线上的批量烧录任务。主要目的是帮助开发者选择合适的编程工具和技术手段,提高工作效率,减少因误操作导致设备损坏的风险。 其他说明:文中提供的代码片段和命令行指令可以直接用于实际项目中,同时附带了一些实用技巧,如防止芯片变砖的小贴士和自动化重试脚本,有助于解决常见的烧录难题。
汉字字库存储芯片扩展实验 # 汉字字库存储芯片扩展实验 ## 实验目的 1. 了解汉字字库的存储原理和结构 2. 掌握存储芯片扩展技术 3. 学习如何通过硬件扩展实现大容量汉字字库存储 ## 实验原理 ### 汉字字库存储基础 - 汉字通常采用点阵方式存储(如16×16、24×24、32×32点阵) - 每个汉字需要占用32字节(16×16)到128字节(32×32)不等的存储空间 - 国标GB2312-80包含6763个汉字,需要较大存储容量 ### 存储芯片扩展方法 1. **位扩展**:增加数据总线宽度 2. **字扩展**:增加存储单元数量 3. **混合扩展**:同时进行位扩展和字扩展 ## 实验设备 - 单片机开发板(如STC89C52) - 存储芯片(如27C256、29C040等) - 逻辑门电路芯片(如74HC138、74HC373等) - 示波器、万用表等测试设备 - 连接线若干 ## 实验步骤 ### 1. 单芯片汉字存储实验 1. 连接27C256 EPROM芯片到单片机系统 2. 将16×16点阵汉字字库写入芯片 3. 编写程序读取并显示汉字 ### 2. 存储芯片字扩展实验 1. 使用地址译码器(如74HC138)扩展多片27C256 2. 将完整GB2312字库分布到各芯片中 3. 编写程序实现跨芯片汉字读取 ### 3. 存储芯片位扩展实验 1. 连接两片27C256实现16位数据总线扩展 2. 优化字库存储结构,提高读取速度 3. 测试并比较扩展前后的性能差异 ## 实验代码示例(单片机部分) ```c #include <reg52.h> #include <intrins.h> // 定义存储芯片控制引脚 sbit CE = P2^7; // 片选 sbit OE = P2^6; // 输出使能 sbit
测控装备干扰源快速侦测系统设计研究.pdf
嵌入式八股文面试题库资料知识宝典-【开发】嵌入式开源项目&库&资料.zip
嵌入式八股文面试题库资料知识宝典-百度2022年嵌入式面试题.zip
少儿编程scratch项目源代码文件案例素材-空间站.zip
基于关联规则的商业银行个性化产品推荐.pdf
嵌入式八股文面试题库资料知识宝典-Linux基础使用.zip
内容概要:本文详细介绍了利用MATLAB进行轴棱锥生成贝塞尔高斯光束及环形光束光强图像的仿真研究。首先阐述了实验的背景与目标,强调了MATLAB在光学和计算科学领域的广泛应用。接着,具体描述了实验的方法与步骤,包括材料准备、仿真过程中的参数设定和光束生成代码编写。最后,对实验结果进行了深入分析,展示了贝塞尔高斯光束和环形光束的光强分布特点,验证了其光学性能的预期表现。文章还对未来的研究方向和技术改进提出了展望。 适合人群:从事光学、物理学及相关领域研究的专业人士,特别是对光束生成和光学性能分析感兴趣的科研工作者。 使用场景及目标:适用于需要进行光束生成和性能分析的实验室环境,旨在帮助研究人员更好地理解和优化光束特性和传播行为。 其他说明:本文不仅提供了详细的实验方法和步骤,还附有丰富的实验结果和数据分析,为后续研究提供了宝贵的参考资料。
内容概要:本文探讨了三电平NPC型有源电力滤波器(APF)的模型预测控制(MPC)中存在的开关频率过高问题及其解决方案。传统MPC方法会导致极高的开关频率,增加了系统的能耗和热量。通过引入滞环控制模块,可以在不大幅牺牲性能的情况下有效降低开关频率。具体来说,滞环控制通过在价值函数计算后增加一个判断条件,对状态切换进行惩罚,从而减少不必要的开关动作。实验结果显示,开关频率从4392Hz降至3242Hz,降幅达26.2%,虽然电流总谐波畸变率(THD)略有上升,但仍符合国家标准。此外,文中还提出了动态调整滞环宽度的方法,以进一步优化不同负载条件下的表现。 适合人群:从事电力电子、电力系统控制领域的研究人员和技术人员,特别是关注APF和MPC技术的人群。 使用场景及目标:适用于需要优化APF系统开关频率的研究和工程项目,旨在提高系统效率并降低成本。目标是在不影响系统性能的前提下,显著降低开关频率,减少能量损失和热管理难度。 其他说明:文章不仅提供了理论分析,还包括具体的实现代码片段,有助于读者理解和实践。同时,强调了在实际应用中需要注意的问题,如中点电位漂移等。
内容概要:本文介绍了三维POD DMD程序在处理原网格数据方面的独特优势和技术细节。首先阐述了该程序能读取结构化和非结构化网格数据及其拓扑关系,在生成模态数据过程中保持原始网格形态而不需要进行网格插值操作。接着展示了简化版本的Python代码片段,揭示了读取网格数据和生成模态数据的核心逻辑。最后提到提供的辅助学习资料如代码、视频教程、Word教程和实例数据,帮助用户深入理解并掌握该程序的应用。 适合人群:从事计算流体力学领域的研究人员和技术爱好者,尤其是那些希望提高数据处理效率的人群。 使用场景及目标:适用于需要处理复杂网格数据的研究项目,旨在简化数据处理流程,提升工作效率,同时保持数据的原始特性。 其他说明:文中不仅提供了理论性的讲解,还有具体的代码示例和丰富的学习资源,使读者可以边学边练,快速上手。
融合双向路由注意力的多尺度X光违禁品检测.pdf
嵌入式八股文面试题库资料知识宝典-Linux_Shell基础使用.zip
嵌入式八股文面试题库资料知识宝典-联发科2021武汉嵌入式软件开发.zip
基于有限体积法Godunov格式的管道泄漏检测模型研究.pdf
嵌入式八股文面试题库资料知识宝典-ARM常见面试题目.zip
基于LWR问题的无证书全同态加密方案.pdf
嵌入式八股文面试题库资料知识宝典-符坤面试经验.zip
内容概要:本文详细探讨了三电平逆变器在带不平衡负载条件下的仿真研究。主要内容包括仿真环境的搭建、不同拓扑结构的选择(如T型、I型NPC和ANPC)、延时相消法(DSC)和双二阶广义积分器(DSOGI)的正负序分离控制策略、SVPWM或SPWM调制技术的应用、双闭环PI控制以及直流均压控制。文中通过具体的参数设置(交流电压220V,直流侧电压750V)进行了详细的仿真实验,并展示了各个控制策略的效果。最终,通过仿真实验验证了所提出方法的有效性,确保了交流侧三相电压波形的对称性和电流波形的自适应调节。 适合人群:从事电力电子、电机驱动、新能源发电等领域研究的技术人员和研究人员。 使用场景及目标:适用于需要理解和掌握三电平逆变器在复杂负载条件下控制策略的研究人员和技术人员。目标是提高对三电平逆变器及其控制策略的理解,优化实际应用中的性能。 其他说明:本文不仅提供了理论分析,还包含了具体的仿真步骤和代码实现,有助于读者更好地理解和应用相关技术。
内容概要:本文介绍了如何使用Matlab/Simulink软件构建一个14自由度的四轮驱动-四轮转向(4WID-4WIS)整车动力学模型。该模型涵盖了整车纵向、横向、横摆、车身俯仰、侧倾、垂向跳动及四轮旋转和垂向自由度等多个方面,旨在全面反映车辆在不同工况下的动态行为。文中详细描述了各子系统的建模方法,包括转向系统、整车系统、悬架系统、魔术轮胎pac2002、车轮系统和PI驾驶员模块。同时,提供了Simulink源码文件、建模说明文档及相关参考资料,便于用户理解和应用。 适用人群:主要面向汽车工程师、研究人员以及对汽车动力学和Simulink建模感兴趣的学习者。 使用场景及目标:①帮助用户深入了解车辆在各种工况下的动态行为;②为车辆控制策略的制定提供理论支持和技术手段;③作为学习和研究整车动力学建模的有效工具。 其他说明:该模型采用模块化建模方法,提高了模型的清晰度和可维护性,同时也提升了建模效率。