Python Lambda 除了会定义执行,还应知道用在哪些编程场景中

在许多编程语言如:C#、Java 语法里都有 lambda 表达式,Python也不例外,概念上来讲 Python lambda 是小巧的匿名函数,1958 年 LISP 首先采用匿名函数。相对于标准函数,它的语法更简洁,但要求更严格。

本文我们一起来学习 lambda 表达式的定义及应用,课程中的以下术语可以互换

  • lambda 表达式
  • lambda 函数
  • 匿名函数

标准函数

由于 lambda 函数是对标准函数的简化,所以首先我们要了解标准函数的定义。

标准函数用来封装代码逻辑,便于重复执行

函数定义:

标准函数定义

前例代码我们可以看到函数的定义有以下几个要素:

函数头:

  • 以 def 关键字声明
  • 定义函数名称,例:hello, say_hello, add
  • 声明参数(可以为空),例:name,a,b

函数体:

  • 包含代码逻辑
  • 根据需要可选是否返回值
  • return 声明返回值
  • 默认返回 None

函数调用

标准函数调用

在需要的地方写函数名以执行函数

定义函数时的参数,如果前例的:name, 或 a, b 为形式上的参数,在执行函数时应传递实际参数,即实参。

Python lambda 表达式

lambda 表达式即匿名函数,也意味着不需要取名,接下来我们分别将前例的三个函数用 lambda 表达式来实现。

使用 lambda 关键字声明,我们首先定义前例中的 hello() 函数的匿名形式

lambda 函数定义

根据代码我们可推断 lambda 表达式冒号 “:” 前半部分相当于标准函数的函数头,后半部分相当于函数体,区别在于此处使用 lambda 关键字声明,且无函数名称。

接下来我们看刚定义的匿名函数怎样执行,由于其未定义名称,没办法像标准函数一样使用 “名称()” 这种形式调用执行,如果你是刚刚定义完 lambda 表达式,Python 里可以使用下划线 “_” 作为最后一个对象的引用符号,则可以这样运行:

执行匿名函数

如果打算更方便的找到定义的匿名函数,也可以在声明时将其赋予一个变量名称,以下是定义和调用代码:

将匿名函数赋予变量

同理,我们分别将前例中的 “say_hello(name)” 和 “add(a, b)” 使用 lambda 表达式实现, 此处注意将标准函数的形参定义在表达式的冒号“:”前:

执行带参匿名函数

细心的同学可能已经发现在计算 a, b 之和的 lambda 表达式内并没有使用 "return" 关键字,这在匿名函数中是可以省略的。

由案例代码我们可以观察到几个方面:

  • 定义形式上的不同
  • 由于形式限制,lambda 表达式更适合封装较少的代码逻辑,大量的代码会让匿名函数的逻辑变得复杂
  • 无名称,这也是匿名的本质,但在某些场景下会出现调用执行不便的情况,尽管可以将其赋给一个变量对象,但似乎又违背了“匿名”的初衷。

尽管 lambda 表达式定义及执行并不复杂,但至于什么场景下使用标准函数,什么场景下使用匿名函数,对于初学者来讲依然比较困惑!如果封装的逻辑较复杂,包含的代码量比较多,此时还是推荐使用标准函数来实现。

除了前面我们讲的相对简洁的代码可以使用 lambda 定义外,匿名函数更多的使用场景临时需要定义一个简单的,不需要复用的函数。这种情况是“将一个函数作为另一个函数的参数来运行”场景比较多。没错,这听上去比较拗口,接下来我们看几个案例。

Python 内置函数 map() 是一个映射函数,用于将一个函数操作映射到一个序列中的每一个元素上,再将每个元素的映射结果作为一个可迭代对象返回,这是map() 函数的说明:

map 函数说明

这里 map() 自身是一个函数,它接收两个参数,第二个参数为 *iterables 为一个序列对象,这个很好理解,象 list, tuple 都可以作为其参数。map() 函数的第一个参数 func 就要求为一个“函数”对象,假定我们有这样一个列表,包含一些分数:

定义列表

此时,如果我们想把这里的每个成绩加上2分,再作为一个序列返回,我们有很多实现方法可以选择,比如直接 for...in 遍历操作,或使用列表推导等,如果我打算使用 map() 映射函数操作,则首先需要定义一个函数,接收一个成绩,将成绩加 2 分再返回。然后将这个函数使用 map() 映射到 scores 这个序列上,代码如下:

执行映射操作

注意: add 函数在被当参数传递至 map() 时是当作对象传递的,此处不需要添加括号,它会在执行时逐一映射到序列里的每个元素上,列表元素在被执行时即是 add(n) 里的参数 n,最终结果会返回一个 map映射对象,由于并不直观,所以外侧我们使用list()将其转换为列表,最终得到了加分以后的结果。

此时有小伙伴会觉得这个操作并不如自己循环或遍历操作来的直观,但我们想象一个场景,如果针对分值的操作可能不止一种,例如有加有减,每次操作的分值也不同。这种情况下原来的循环遍历,可能要写很多次,且不利于重用。而 map() 配合 lambda 匿名函数就可以很方便的应付这类问题,这里只要把握 map(func, *iterables) 的 "func" 是一个函数,而函数可以由 lambda 定义这个关键点即可。

map 映射 lambda 表达式

在 Python 内置全局或标准库内有很多函数都类似 map(func, ...) 用到另一函数作为参数,实际开发过程中,我们多留意文档或查询参数说明,会对开发工作带来很大帮助!

我们再来看一个较常见的操作,列表排序:

排序列表

代码不难理解,内置全局函数 sorted() 针对列表元素字符串进行升序排序,此时默认是依据首字母来排序的。如果我们要求按每个姓名的最后一个字母排序整个列表该怎么办呢?通过help(sorted()) 我们观察 sorted() 函数说明如下:

sorted 函数说明

其中的参数 key 是一个函数类型参数,用于指定排序的条件,此时,如果我们用标准函数来定义再传递,代码如下:

应用 sorted 函数 key 参数

condition 函数指定排序条件为传入参数的最后一个字符

代码写到这里我们可能已经留意到,这个 condition 函数可能只使用一次,并且函数逻辑也并不复杂,此时是 lambda 表达式应用的最佳场景:

到这一步,相信大家对于 lambda 匿名函数有了进一步的认识,本文抛砖引玉,希望能激起小伙伴们更多的灵感,最后来个小练习,如何一行代码将下列字典表中项按分数降序排序?

尝试按值排序字典表

如果您打算系统学习 Python 语言,可以试听报名我们的专栏课程:

干货原创不易,大家别忘“关注”赞、评、转!!!

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();