2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 函数式编程|python的函数式编程

函数式编程|python的函数式编程

时间:2022-08-10 02:46:38

相关推荐

函数式编程|python的函数式编程

面向过程,面向对象

面向过程:分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了

面向对象:把问题中的事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为

示例:设计棋局

面向过程:

开始游戏,红棋先走展示棋局情况判断战况(是否有棋子被吃、胜负情况)黑棋接着走展示棋局情况判断战况(是否有棋子被吃、胜负情况)……

面向对象:

黑棋和红棋对象:负责棋子的走向,两者行为相同棋盘系统:通过黑棋和红棋对象的行为展示棋局情况规则系统:判断“战场”的变化以及胜负等

优缺点

面向过程

优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

缺点:没有面向对象易维护、易复用、易扩展

面向对象

优点:易维护、复用、扩展,由于面向对象所具有的封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活

缺点:性能比面向过程低

函数式编程(Functional Programming)

函数是Python内建支持的一种封装,通过把大段代码拆成函数,通过一层一层的函数调用就可以把复杂任务分解成简单的任务,这种分解称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元

函数式编程也可以归结到面向过程的程序设计,但其思想更接近数学计算。

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数

函数式编程中要求函数是一等公民

通常通过以下几点来判断函数是否是一等公民

函数可以存储在变量中函数可以作为参数函数可以作为返回值

Python 的函数式编程

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

Python 对函数式编程提供部分支持。主要体现在下面几个方面:

Python 的一些语法,比如lambda、列表解析、字典解析、生成器、iter 等Python 的一些内置函数,包括 map、reduce、filter、all、any、enumerate、zip 等Python 的一些内置模块,比如 itertools、functools 和 operator 模块等Python 的一些第三方库,比如 fn.py, toolz 等Python 将函数视为“第一等公民” – 对象,因此可以作为函数参数也可以作为函数的返回值。包括高阶函数,返回函数,匿名函数,装饰器,偏函数等。

高阶函数

一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数(map, filter, reduce, sorted)

MapReduce: Simplified Data Processing on Large Clusters

map 映射函数

map(function, iterable, …)

接收两个参数,第一个参数 function 以参数序列中的每一个元素调用 function 函数,

返回包含每次 function 函数返回值的新列表返回值是一个迭代器

lst = [1,2,3,4,5,6,7]lst2 = [10,100,1000,10000]def f1(x,y):return x + ymap后面可以接受多个可迭代对象,那传入几个可迭代对象,前面的函数就要接受几个参数print(list(map(f1,lst,lst2)))print(list(map(lambda x,y:x+y, lst, lst2)))

例题:

有列表[1, 2, 3, 4, 5],将所有元素转换成str: [‘1’, ‘2’, ‘3’, ‘4’, ‘5’]

lst = [1,2,3,4,5]print(list(map(str,lst)))

filter 过滤函数

filter(function, iterable)

接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,

然后返回 True 或 False,最后将返回True 的元素放到新列表中返回值是一个迭代器

例如:

去掉偶数,保留奇数[1,2,3,4,5,6,7,8,9]

print(list(filter(lambda x : x % 2, [1,2,3,4,5,6,7,8,9])))

在一个list中,删掉偶数,只保留奇数

lst=['A','','B',None,‘C’,' ','a',1,0]print(list(filter(lambda x:x and str(x).strip(), lst)))

reduce() 函数会对参数序列中元素进行累积。(这个函数用的时候需要导入)

函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

from functools import reduces = [1,3,5,7,9]print(reduce(lambda x,y:x*10+y, s))

sorted 排序函数

sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。

把一个序列中的字符串,忽略大小写排序

list1=['bob','about','Zoo','Credit']print(sorted(list1,key=lambda x:x.lower()))print(sorted(list1,key=str.lower))

按value来排序

d1 = {"a":3,"b":4,"c":2,"d":5}print(dict(sorted(d1.items(), key=lambda x:x[1])))

返回函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

示例:

def lazy_sum(*args):def sum():ax = 0for n in args:ax = ax + nreturn axreturn sum

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)>>> f2 = lazy_sum(1, 3, 5, 7, 9)>>> f1==f2False

f1()和f2()的调用结果互不影响。

闭包

当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行

def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fsf1, f2, f3 = count()

实际结果是

>>> f1()9>>> f2()9>>> f3()9

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

def count():def f(j):def g():return j*jreturn gfs = []for i in range(1, 4):fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()return fs

结果:

>>> f1, f2, f3 = count()>>> f1()1>>> f2()4>>> f3()9

nonlocal

使用闭包,就是内层函数引用了外层函数的局部变量。如果只是读外层变量的值,我们会发现返回的闭包函数调用一切正常:

def inc():x = 0def fn():# 仅读取x的值:return x + 1return fnf = inc()print(f()) # 1print(f()) # 1

使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。

匿名函数

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

>>> f = lambda x: x * x>>> f<function <lambda> at 0x101c6ef28>>>> f(5)25

同样,也可以把匿名函数作为返回值返回,比如:

def build(x, y):return lambda: x * x + y * y

装饰器

偏函数

functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单

>>> import functools>>> int2 = functools.partial(int, base=2)>>> int2('1000000')64>>> int2('1010101')85

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。