在本文中,您将了解什么是函数式范式以及如何在Python中使用函数式编程。在Python中,函数式编程中的映射和过滤器可以做与列表相同的事情。这打破了Python的禅宗规则之一,因此函数式编程的这些部分不被视为“Pythonic”。但是因为函数式编程是通向高级编程的必经之路,所以我们需要了解甚至掌握它。命令式范式和函数式范式首先比较一下命令式范式在编程中的两个概念:在命令式范式中,你给计算机一个任务序列来完成任务,它执行这些任务。在执行它们时,它可以改变状态。例如,假设您最初将A设置为5,然后您更改A的值,您有变量,在这个意义上,变量内的值发生变化。在功能范式中,你不告诉计算机做什么,而是告诉它做什么。比如:一个数的最大公约数是多少,1到n的积是多少等等。因此,不能更改变量。一旦你设置了一个变量,它就会永远保持这种状态(请注意,它们在纯函数式语言中不被称为变量)。所谓“副作用”(sideeffect)是指函数内部和外部相互作用(最典型的情况是修改全局变量的值),导致产生除操作之外的其他结果。函数式编程强调没有“副作用”,也就是说函数要保持独立,所有的函数都是返回一个新的值,没有其他行为,尤其是外部变量的值一定不能被修改。让我们看一个典型的Python代码示例:a=3defsome_func():globalaa=5some_func()print(a)这段代码的输出是5。在函数范式中,改变变量是一个大禁忌,让功能影响其范围之外的事物也是一个很大的禁忌。函数唯一能做的就是计算并返回结果。现在您可能会想:“没有变量,就没有副作用吗?”那有什么好处?如果用相同的参数调用一个函数两次,那么它必须返回相同的结果。因为函数没有副作用,所以如果您正在构建一个计算程序,您可以加快程序的速度。如果程序知道func(2)等于3,我们可以将它存储在一个表中。这可以防止程序在我们已经知道答案的情况下重复运行相同的函数。Map要理解map,我们先来看看iterables是什么。iterable是任何可以迭代的东西。通常这些是列表或数组,但Python有许多不同类型的迭代器。您甚至可以创建自己的对象,这些对象可以使用Python的魔法方法进行迭代。这里有两个方法:第一个使这个对象可迭代的魔术方法returnselfdef__next__(self):#第二个魔术方法ifself.current>self.high:raiseStopIterationelse:self.current+=1returnself.current-1"magicmethodIt是python的内置方法,不需要主动调用,它存在的目的就是为了调用python的解释器,几乎每一个magic方法都有对应的内置函数或者运算符,当我们使用这些函数的时候或者对这个对象进行操作指定字符时会调用类中对应的magic方法,可以理解为重写内置函数。第一个魔术方法是使用“__iter__”返回迭代对象,通常在循环开始时使用。如果我们运行:forcinCounter(3,8):print(c)那么它将输出:345678在Python中,迭代器是一个具有简单魔术方法的对象。这意味着您可以访问对象内的位置,但不能遍历对象。某些对象将使用方法__next__,如上面代码中的第二个示例。现在我们知道什么是可迭代对象,让我们回到map函数。map函数允许我们将一个函数应用于可迭代对象中的每个项目。通常,我们希望对列表中的每个项目应用一个函数,但请注意,这对于大多数迭代器都是可行的。Map接受两个输入,要应用的函数和可迭代对象:map(function,iterable)假设我们有一个列表:[1,2,3,4,5]我们希望列表中的每个数字都是正方形的,那么你可以这样写代码:x=[1,2,3,4,5]defsquare(num):returnnum*numprint(list(map(square,x)))Python函数是惰性的。如果我们的代码中不包含“list()”,该函数将存储迭代定义而不是列表。我们需要明确地告诉Python“将其转换为列表”,以便我们可以使用它。现在写一个像“square(num)”这样的普通函数就好了,但是看起来不对。我们必须定义一个完整的函数才能在地图中使用一次?我们可以使用lambda(匿名)函数在映射中定义一个函数。lambda表达式lambda表达式是一个单行函数。例如,这个lambda表达式对给定数求平方:square=lambdax:x*x运行程序:>>>square(3)9告诉Python这是一个lambda函数,输入称为x,之后的内容冒号是你对输入的操作,它会自动返回结果。现在我们可以简化上面的程序:x=[1,2,3,4,5]print(list(map(lambdanum:num*num,x)))ReduceReduce是一个函数,它接受一个可迭代的Athingbecomesa事物。通常,您对列表执行计算以将其简化为数字。Reduce的工作方式如下:reduce(function,list)我们可以(而且通常会)将lambda表达式用作函数。列表的乘积是每个单独数字的乘积。为此,您可以:product=1x=[1,2,3,4]fornuminx:product=product*num但是对于reduce,您可以这样写:fromfunctoolsimportreduceproduct=reduce((lambdax,y:x*y),[1,2,3,4])Filter过滤函数接受一个可迭代对象并过滤掉该可迭代对象中不需要的所有内容。filter通常接受一个函数和一个列表。它对列表中的每一项应用一个函数,如果函数返回True,它什么都不做。如果它返回False,则该项目将从列表中删除。语法如下:filter(function,list)让我们看一个小例子,没有filter我们会这样写:x=range(-5,5)new_list=[]fornuminx:ifnum<0:new_list.append(num)使用filter这变成:x=range(-5,5)all_less_than_zero=list(filter(lambdanum:num<0,x))高阶函数高阶函数可以将函数作为参数并返回一个函数.一个很简单的例子如下:defsummation(nums):returnsum(nums)defaction(func,numbers):returnfunc(numbers)print(action(summation,[1,2,3]))partialapplication部分应用程序(又名闭包)有点奇怪,但非常酷。您可以在不提供函数所需的所有参数的情况下调用函数。让我们看一个例子。我们想创建一个函数,它接受两个参数,一个底数和一个指数,并返回底数的指数次方,如下所示:defpower(base,exponent):returnbase**exponent现在我们想要一个专门的的平方函数,使用幂函数求一个数的平方:defsquare(base):returnpower(base,2)这行得通,但是如果我们想要一个立方函数呢?或者它是函数的4次方?我们可以继续写吗?好吧,你可以。但是程序员是懒惰的。如果你一遍又一遍地重复同样的事情,这表明有一种更快的方法可以加快速度,这样你就不会重复了。我们可以在这里使用部分应用程序。让我们看一个使用部分应用的平方函数的例子:fromfunctoolsimportpartialsquare=partial(power,exponent=2)print(square(2))这很酷吗?我们可以调用一个带有两个参数的函数,然后只使用一个参数告诉Python第二个参数是什么。
