了解Python中的四个高级函数概念

> Photo by Tim Swaan on Unsplash.

Python函数是一段代码,可在需要运行时执行特定的操作,我们称其为函数。 大多数时候,我们使用以下语法声明并调用函数:

在上面的代码中,我们使用def关键字声明了一个名为add_up的函数。 此函数将两个数字(num1和num2)作为输入参数,计算它们的总和作为已定义的运算,然后将此值作为函数的输出返回。 很简单吧?

除了这些常规函数外,Python中还有其他种类的函数可以使我们的开发受益。 让我们在本文中对其进行回顾。

Lambda函数

Lambda函数是小的匿名单行函数。 有时,我们可以简单地将它们称为lambda。 Lambda具有以下语法:

lambda arguments: expression

我们使用lambda关键字声明一个lambda函数。 在此关键字之后,我们指定参数列表,其数量可以从零到多个变化。 然后,我们指定要执行的操作,称为lambda函数的表达式。

如您所见,lambda具有非常简洁的语法,因此它们最适合需要简短的一次性使用功能的场景。 让我们考虑以下示例。 sorted()函数用于根据key参数指定的key函数对可迭代对象进行排序:

>>> # define a list of tuples
>>> records = [(1, 'John'), (2, 'Aaron'), (5, 'Ian')]
>>> # sort with a lambda
>>> sorted(records, key=lambda x: len(x[1]))[(5, 'Ian'), (1, 'John'), (2, 'Aaron')]

在上面的代码中,我们首先定义一个列表来存储一些学生及其学生ID和姓名的记录。 然后,我们使用lambda函数对它们进行排序,该函数按学生姓名的长度对列表进行排序。

有关使用lambda函数进行排序的信息,请参阅我的上一篇文章。 同样重要的是要知道可能会滥用lambda。 为了方便起见,提供了以下文章:

闭包

闭包是嵌套函数,可捕获外部函数的非局部变量。 我认为从概念上理解闭包并不容易。 透彻的理解需要深入了解范围和函数(它们是Python中的一流对象)。 出于本文的目的,让我们通过看一个具体的示例来总体了解闭包:

>>> # create a closure
>>> def make_multiplier(coefficient):
... product = 1
...
... def multiplier():
... nonlocal product
... product *= coefficient
... return product
...
... return multiplier
...

在上面的代码中,我们定义了一个名为make_multiplier的函数。 因为它包含另一个函数乘法器,所以我们可以将make_multiplier称为外部函数,并将multiplier称为嵌套函数。 外部函数返回嵌套函数作为其返回值。 重要的是,嵌套函数使用并修改在外部函数范围内定义的非局部变量(即乘积)。 综上所述,在Python中创建闭包包含三个关键要素:

· 在外部函数的范围内声明一个嵌套函数。

· 嵌套函数范围之外的非局部变量的绑定。

· 返回嵌套函数以输出闭包函数。

我们如何使用闭包? 让我们看下面的简单例子:

>>> multipler3 = make_multiplier(3)
>>> multipler3()
3
>>> multipler3()
9
>>> multipler3()
27
>>> multipler3.__code__.co_freevars
('coefficient', 'product')
>>> multipler3.__closure__[1].cell_contents
27

然后,我们声明一个名为multiplier3的闭包。 每次我们称此闭包为乘积乘以3。 换句话说,封盖"记住"产品最后一次使用后的状态。 相关概念包括变量绑定和值捕获。 我们可以通过调用__code __。co_freevars和__closure __ [1] .cell_contents来检查相关信息。

装饰器

装饰器是可扩展其他功能的行为而无需显式修改它们的功能。 本质上,装饰器是一种高阶函数,定义为将其他函数作为输入或将其他函数作为输出返回的函数。 通过下面的示例,让我们真正了解装饰者:

>>> def clap():
... print("Clap! Clap!")
...
>>> # define a higher order function
>>> def triple_repeat_wrapper(func):
... def wrapper():
... print(f"Before calling func {func.__name__}")
... func()
... func()
... func()
... print(f"After calling func {func.__name__}")
... return wrapper
...

在上面的代码中,我们定义了两个函数(clap和Triple_repeat_wrapper),后者是一个高阶函数,该函数在嵌套包装函数中调用传递的func三次,然后将包装函数作为高阶函数的输出返回。

我们如何使用这些功能? 如下代码所示,我们创建了一个称为wrapd_clap的函数,该函数将拍手函数传递给高阶函数Triple_repeat_wrapper。 如您所见,调用wrapped_clap函数将导致嵌套包装器函数内部的代码被调用。 与打印输出一致,我们知道wrapped_clap函数引用了嵌套函数包装器。

>>> wrapped_clap = triple_repeat_wrapper(clap)
>>> wrapped_clap()
Before calling func clap
Clap! Clap!
Clap! Clap!
Clap! Clap!
After calling func clap
>>> wrapped_clap
.wrapper at 0x1038f0680>

但是,回想一下,当您看到一些有关装饰器的示例代码时,您肯定已经看到了@符号的用法。 这个符号如何与我们上面定义的功能一起发挥作用? 让我们通过参考以下代码来解决这个问题:

>>> @triple_repeat_wrapper
... def hooray():
... print("Hooray! Hooray!")
...
>>> hooray()
Before calling func hooray
Hooray! Hooray!
Hooray! Hooray!
Hooray! Hooray!
After calling func hooray
>>> hooray
.wrapper at 0x1038f0830>

在上面的代码中,我们声明了一个名为hooray的函数。 当我们调用此函数时,输出的格式与前一个wrapd_clap函数的输出相同。 同样,hooray函数引用嵌套包装器函数。

为什么会这样? 您可能已经注意到,在此hooray函数的声明上方,我们在Triple_repeat_wrapper函数名称之前使用@符号。 这只是装饰者的语法糖。 本质上,我们告诉Python解释器,我们将要定义的函数将由decorator函数包装。

Curry

以数学家Haskell Curry的名字命名的currying是指通过应用部分参数从现有函数创建新函数。 因此,该概念有时也称为部分功能。

与上述概念相比,这一概念更容易理解。 让我们考虑下面的简化示例,使用与上面定义的相同的add_up函数:

>>> # define a function returns a value
>>> def add_up(num1, num2):
... sum_n = num1+num2
... return sum_n
...
>>> # define a partial function that adds seven
>>> add_seven = lambda x: add_up(7, x)
>>> add_seven(10)
17
>>> add_seven(72)
79
>>> # use a regular def keyword
>>> def add_eight(x):
... return add_up(8, x)
...
>>> add_eight(10)
18

在上面的代码中,我们使用lambda函数将数字7设置为add_up函数的第一个参数。 换句话说,创建的add_seven函数是原始add_up的部分函数,第一个参数始终设置为7。除了使用lambda函数之外,使用常规方法通过def关键字定义函数当然是可以接受的。

functools模块中提供了另一个方便的用于创建部分功能的工具。 考虑以下示例。 我们使用partial函数创建add_ten函数,该函数的默认参数为10,该函数调用add_up函数:

总结

在本文中,我们回顾了Python函数基础之外的四个高级概念。 以下是这些概念的简要概述:

· Lambda是匿名函数,在需要简单的一次性内联函数的情况下非常方便。

· 闭包是嵌套函数,它们绑定周围范围的非局部变量。

· 装饰器是可修改其他功能的行为的高阶功能。

· Currying是我们通过设置一些默认参数从现有函数中创建部分函数的方法。

(本文翻译自Yong Cui, Ph.D.的文章《Python Functions: Lambdas, Closures, Decorators, and Currying》,参考:

https://medium.com/better-programming/python-functions-lambdas-closures-decorators-and-currying-83165d099abe)