当前位置: 首页 > 科技观察

Python函数式编程,就看这篇文章吧!

时间:2023-03-12 22:17:54 科技观察

本文对Python中的函数式编程技术进行了简单的介绍。一等函数在Python中,函数是“一等公民”。即函数与其他数据类型如int等处于平等地位。因此,我们可以将函数赋值给变量,将它们作为参数传递给其他函数,将它们存储在其他数据结构(如字典)中,并作为值从其他函数返回。将函数视为对象由于字符串、列表和整数等其他数据类型都是对象,因此函数在Python中也是对象。让我们看一下示例函数foo,它打印出它的名称:deffoo():print("foo")由于函数是对象,我们可以将函数foo分配给任何变量,然后调用该变量。例如,我们可以将函数赋值给变量bar:bar=foobar()#willprint"foo"totheconsole语句bar=foo将函数foo引用的对象赋值给变量bar。将对象视为函数当对象可调用时,它们与函数相同,例如object()。这是通过__call__方法实现的。一个例子如下:classGreeter:def__init__(self,greeting):self.greeting=greetingdef__call__(self,name):returnself.greeting+""+name每次我们配置一个Greeter类的对象时,我们将创建一个新的,您可以在打招呼时调用的新名称。如下:morning=Greeter("goodmorning")#createsthecallableobjectmorning("john")#callingtheobject#prints"goodmorningjohn"totheconsole我们可以调用morning对象的原因是我们已经在该类定义中使用了__call__方法。为了检查对象是否可调用,我们使用内置函数callable:callable(morning)#truecallable(145)#false。int不可调用。数据结构中的函数函数可以像其他对象一样存储在数据结构中。例如,我们可以创建一个int到func的字典。当int是要执行的步骤的简写时,这会派上用场。#存储在字典中mapping={0:foo,1:bar}x=input()#从usermapping[x]()中获取整数值#调用字典访问返回的函数同样,函数也可以存储在其他各种数据中结构。使用函数作为参数和返回值函数也可以作为其他函数的参数和返回值。接受函数作为输入或返回函数的函数称为高阶函数,是函数式编程的重要组成部分。高阶函数具有强大的功能。正如《Eloquent JavaScript》中所解释的:“高阶函数允许我们对动作执行抽象,而不仅仅是抽象值。”让我们看一个例子。假设我们要遍历项目列表并按顺序打印它们。我们可以很容易地构建一个迭代函数:defiterate(list_of_items):foriteminlist_of_items:print(item)看起来很酷,但这只是一级抽象。如果我们想在遍历列表时做一些打印以外的事情怎么办?这就是高阶函数的用途。我们可以创建一个函数iterate_custom,其中要迭代的列表和应用于每个项目的函数是iterate_custom函数的输入:defiterate_custom(list_of_items,custom_func):foriteminlist_of_items:custom_func(item)其实很厉害。我们将抽象级别提高了一个级别以使代码更可重用。现在,我们不仅可以在打印列表时调用该函数,还可以对涉及序列迭代的列表进行任意操作。函数也可以返回,这让事情变得更简单。就像我们将函数存储在字典中一样,我们也可以将函数作为控制语句来确定哪些函数是合适的。例如:defadd(x,y):returnx+ydefsub(x,y):returnx-ydefmult(x,y):returnx*ydefcalculator(opcode):ifopcode==1:return添加elif操作码==2:returnsubelse:returnmultmy_calc=calculator(2)#mycalc是一个减法器my_calc(5,4)#returns5-4=1my_calc=calculator(9)#mycalc现在是一个乘法器my_calc(5,4)#returns5x4=20.嵌套函数函数也可以在其他函数内部,这就是“内部函数”。内在函数对于创建辅助函数很有用,辅助函数是充当子模块以支持主函数的小型可重用函数。当问题需要特定的函数定义(参数类型或顺序)时,我们可以使用辅助函数。这种非常规的操作使得解决问题变得更加容易。例如,请参阅:http://www-inst.eecs.berkeley.edu/~cs61a/sp12/lectures/lect4-2x3.pdf。假设你想定义一个只有一个参数n的斐波那契函数fib(n)并且我们必须返回第n个斐波那契数。定义此类函数的一种可能方法是使用辅助函数来跟踪斐波那契数列的前两项(因为斐波那契数是前两项的总和)。deffib(n):deffib_helper(fk1,fk,k):如果n==k:returnfkelse:returnfib_helper(fk,fk1+fk,k+1)如果n<=1:returnnelse:returnfib_helper(0,1,1)将计算从函数体转移到函数参数,非常强大。因为它减少了递归方法中可能出现的冗余计算。单表达式函数(Lambda表达式)如果我们想编写一个函数而不给函数命名怎么办?如果我们想写一个简短的单行函数怎么办(如上面示例中的函数foo或mult)?我们可以使用lambda关键字在Python中定义此类函数。示例如下:mult=lambdax,y:x*ymult(1,2)#returns2mult函数的行为与使用传统def关键字定义的行为相同。注意:lambda函数必须是单行的,不能包含程序员编写的return语句。事实上,它们往往有一个隐式的return语句(在上面的例子中,函数想要表达returnx*y,但是我们在lambda函数中省略了显式的return语句)。lambda函数更强大和精确,因为我们还可以构建匿名函数(即没有名称的函数):(lambdax,y:x*y)(9,10)#returns90whenwewon'tneedtousea函数一次,这个方法很方便。比如当我们要填充一个字典时:importcollectionspre_fill=collections.defaultdict(lambda:(0,0))#所有的字典键和值都设置为0接下来我们看Map、Filter和Reduce来理解更多拉姆达。Map、Filter和ReduceMapmap函数根据指定的过程(函数)将一个输入集转换为另一个集。这类似于上面提到的iterate_custom函数。例如:defmultiply_by_four(x):returnx*4scores=[3,6,8,3,5,7]modified_scores=list(map(multiply_by_four,scores))#modifiedscores现在是[12,24,32,12,20,28]在Python3中,为方便起见,可以将map函数返回的map对象转换为列表。现在,我们不再显式定义multiply_by_four函数,而是定义lambda表达式:modified_scores=list(map(lambdax:4*x,scores))当我们想对集合中的所有值执行操作时,map函数很有用。过滤顾名思义,过滤功能可以帮助过滤掉不需要的项目。例如,如果我们想去除分数中的奇数,那么我们可以使用过滤器:even_scores=list(filter(lambdax:Trueif(x%2==0)elseFalse,scores))#even_scores=[6,8]由于提供给过滤器的函数决定是否单独接受每一项,因此该函数必须返回一个布尔值,并且该函数必须是一元的(即只接受一个输入参数)。Reduce函数用于“总结”或“概括”一个数据集。比如我们要计算所有分数的总和,可以使用reduce:sum_scores=reduce((lambdax,y:x+y),scores)#sum_scores=32这比写循环语句简单多了。注意:为reduce提供的函数需要两个参数:一个代表正在检查的项目,另一个代表所用操作的累积结果。本文是一篇关于函数式编程的入门文章。虽然把相关的知识介绍的尽量完整,但是没有那么深入。如果您想了解更多,可以阅读以下资源:在Python中使用函数式编程的最佳实践:https://kite.com/blog/python/functional-programming/FunctionalProgrammingTutorialsandNotes:https://www.hackerearth.com/en/practice/python/functional-programming/functional-programming-1/tutorial/