在本文中,你将学习什么是函数式范式,以及如何使用Python进行函数式编程。您还将了解列表理解和其他形式的理解。功能范式在命令式范式中,任务是通过给计算机一系列指令然后执行它们来完成的。在执行这些指令时,可以更改某些状态。例如,假设您最初将A设置为5,然后更改A的值。此时,您更改了变量内部值意义上的A的状态。在功能范式中,您不会告诉计算机做什么,而是告诉计算机它是什么。比如数的最大公约数是多少,1到n的乘积是多少等等。因此,变量不能改变。一旦你设置了一个变量,它就永远保持这种状态(注意在纯函数式语言中它们不是变量)。因此,函数式编程没有副作用。副作用是当函数改变自身以外的东西时。让我们看一些典型的Python代码示例:这段代码的输出是5。在函数式范例中,改变变量是一个很大的禁忌,并且拥有影响其范围之外的事物的函数也是一个很大的禁忌。函数唯一能做的就是计算一些东西并将其作为结果返回。现在您可能会想:“没有变量,没有副作用?为什么这样好?”这是一个很好的问题,我相信大多数人都想知道这个问题。如果使用相同的参数调用一个函数两次,则可以保证返回相同的结果。如果您研究过数学函数,就会知道这个好处。这称为引用透明性。由于函数没有副作用,如果你正在构建一个计算某些东西的程序,你可以加快程序的速度。如果每次调用func(2)都返回3,我们可以将其存储在表中,这样可以防止程序重复运行相同的函数。通常,在函数式编程中,我们不使用循环。我们使用递归。递归是一个数学概念,通常表示“调用自身”。使用重复调用自身的递归函数作为子函数。这是Python中递归函数的一个很好的例子:一些编程语言也是惰性的。这意味着他们直到最后一秒才计算或做任何事情。如果你写一些代码做2+2,函数程序只会在你真正需要使用结果的时候才计算。我们很快就会探索Python中的惰性。为了理解Map,我们先来看看迭代是什么。通常可以迭代的对象是列表或数组,但Python有许多不同的类型可以迭代。您甚至可以创建自己的对象,这些对象可以通过实施魔法方法进行迭代。魔术方法就像一个API,可以帮助您的对象更加Pythonic。你需要实现2个魔法方法来使一个对象可迭代:第一个魔法方法“\_\_iter\_\_”(注意:这里是双下划线)返回可迭代对象,通常在循环开始时使用。"\_\_next\_\_"返回下一个对象。让我们快速进入一个终端并调用上面的代码:run将在Python中打印出来,迭代器是一个只有\_\_iter\_\_魔法方法的对象。这意味着您可以访问对象内的位置,但不能遍历对象。有些对象会有魔法方法\_\_next\_\_而不是\_\_iter\_\_魔法方法,例如集合(在本文后面讨论)。对于本文,我们假设我们接触的所有东西都是一个可迭代对象。现在我们知道什么是可迭代对象,让我们回到map函数。map函数允许我们将一个函数应用于可迭代对象中的每个项目。Map需要2个输入,即要应用的函数和一个可迭代对象。假设我们有一个数字列表如下:我们想要对每个数字进行平方,我们可以编写如下代码:Python中的函数式函数是惰性的。如果我们不使用“列表”,该函数将存储可迭代的定义,而不是列表本身。我们需要显式地告诉Python“把它变成一个列表”供我们使用。在Python中突然从非惰性求值变为惰性求值有点奇怪。如果你更多地以功能性思维方式思考而不是命令式思维方式,你最终会习惯的。现在写一个像“square(num)”这样的普通函数是可以的,但这是错误的。我们必须定义一个完整的函数才能在地图中使用它?好吧,我们可以使用lambda(匿名)函数在映射中定义一个函数。Lambda表达式lambda表达式是只有一行的函数。例如,这个lambda表达式计算给定数字的平方:让我们运行它:这看起来不像一个函数吗?好吧,这有点令人困惑,但可以解释。我们给变量“square”赋值。这个怎么样:告诉Python这是一个lambda函数,输入称为x。冒号后的任何内容都是您对输入所做的操作,它会自动返回结果。将我们的方形程序简化为一行代码,我们可以这样做:因此在lambda表达式中,所有参数都在左侧,而您要对它们执行的操作在右侧。有点乱。但事实是,编写只有其他函数式程序员才能阅读的代码有一定的乐趣。此外,将一个函数变成一行代码也很酷。ReduceReduce是一个将迭代变成事物的函数。通常,您可以对列表使用reduce函数来执行计算以将其缩减为单个数字。Reduce看起来像这样:我们经常将lambda表达式用作函数。列表的乘积是每个单独的数字相乘。为此,您可以编写如下代码:但是使用reduce您可以编写:获得相同的功能,代码更短,并且在函数式编程的情况下更清晰。(注意:reduce函数不是Python3的内置函数,需要从functools模块中引入)Filterfilter函数使用一个iterable,过滤掉iterable中所有你不需要的内容。通常,过滤器接受一个函数和一个列表。它对列表中的每一项应用一个函数,如果函数返回True,它什么也不做。如果它返回False,则该项目将从列表中删除。语法如下:让我们看一个小例子,没有过滤器我们会这样写:使用过滤器,你可以这样写:Python,作为一门不断发展和流行的语言,还在不断更新。学习的时候,建议找一些学习伙伴一起学习讨论,效果更好。如果你想学习Python,欢迎加入Python学习交流群(627012464),一起监督,一起学习。有开发工具,有很多干货和技术资料分享!高阶函数高阶函数可以将函数作为参数并返回函数。一个很简单的例子如下:返回函数的第二个例子:一开始我说纯函数式编程语言没有变量。高阶函数使这更容易。Python中的所有函数都是一等公民。一等公民被定义为具有以下一个或多个特征:在运行时创建在数据结构中分配变量或元素作为参数传递给函数作为函数的结果传递返回Python中的所有函数都可以用作高阶函数功能。部分应用部分应用(也称为闭包)有点奇怪,但非常酷。您可以在不提供函数所需的所有参数的情况下调用函数。让我们看一个例子。我们想创建一个函数,它接受2个参数,一个底数和一个指数,并返回底数的指数次方,如下所示:,但是如果我们想要一个立方体函数呢?或者求四次方的函数怎么样?我们可以继续写吗?好吧,你可以。但是程序员是懒惰的。如果您一遍又一遍地重复同一件事,则表明有一种更快的方法可以加快速度,从而避免您重复自己。我们可以在这里使用闭包。让我们看一个使用闭包的square函数的例子:是不是很酷!我们可以只使用1个参数来调用需要2个参数的函数。我们还可以使用循环来生成一个幂函数,该函数实现从立方到1000的幂。函数式编程不是Pythonic正如您可能已经注意到的那样,我们想在函数式编程中做的很多事情都围绕着列表.除了reduce函数和闭包,您看到的所有函数都生成列表。Guido(Python之父)不喜欢Python中的函数式风格,因为Python已经有了自己的生成列表的方式。如果你在Python的交互环境中写“importthis”,你会得到:这就是Python之禅。这是一首关于成为Pythonic意味着什么的诗。我们想要涵盖的部分是:应该有一种——最好只有一种——显而易见的方法来做到这一点。(应该尝试找到一个,最好是唯一明显的解决方案)在Python中,map和filter可以执行与列表理解(下面讨论)相同的操作。这打破了Python之禅的规则,因此函数式编程的这些部分不被视为“pythonic”。另一个主题是Lambda。在Python中,lambda函数是一个普通函数。Lambda是语法糖。这两个语句是等价的。普通函数可以做lambda函数可以做的所有事情,但反过来就不行了。Lambda函数不能做普通函数可以做的所有事情。这是为什么函数式编程不能很好地融入整个Python生态系统的简短论证。您可能已经注意到我之前提到了列表理解,我们现在将讨论它们。ListComprehensions早些时候,我提到过任何你可以用map或filter做的事情,你也可以用listcomprehension来做。列表解析是Python中生成列表的一种方式。语法是:让我们对列表中的每个数字进行平方,例如:我们可以看到函数是如何应用于列表中的每个项目的。我们如何应用过滤器?看前面的代码:我们可以把它变成这样的列表推导式:listssupportstatementslikeif。您不再需要对某些东西应用一百万个函数来获得您想要的东西。事实上,如果您尝试生成某种列表,使用列表推导式看起来更清晰、更容易。如果我们想对列表中小于0的每个数字进行平方怎么办?使用lambda、映射和过滤器,您会编写:这看起来很长很复杂。对于列表推导,就是这样:列表推导仅适用于列表。map,filter适合任何可迭代的对象,那么这个有什么用呢?您可以对遇到的任何可迭代对象使用任何理解。其他派生您可以为任何可迭代对象创建派生。可以使用理解生成任何可迭代对象。从Python2.7开始,您甚至可以生成字典(hashmap)。如果它是可迭代的,则可以生成它。让我们看看最后一组例子。set是一个元素列表,其中没有元素重复两次。集合中的元素是无序的。您可能会注意到set(集合)与dict(字典)具有相同的花括号。Python非常聪明。根据你是否为dict提供值,它会知道你写的是dict派生还是set派生。总结函数式编程美丽而纯粹。函数式代码可以干净,但也可以凌乱。一些Python程序员不喜欢Python中的函数式编程。但我认为你应该使用最好的工具来解决问题。
