没有学不会的python--函数式编程以及高阶函数

没有学不会的python


函数式编程

到现在为止,我们的没有学不会python系列文章已经讲了很多知识点了,如果是第一次刷到这篇文章的朋友可以去我主页看一下以前写的文章。前面讲了很多知识点,每个知识点都辅以代码作为理解和练手,这些例子都是用面向过程思想编写的,面向过程的本质就是将一个个复杂问题拆解成简单问题,意思就是将一个以实现某目的的程序划分成一个个函数的意思,这就是面向过程的编程思想。

而函数式编程,虽然也是面向过程的一种编程思想,但它又跟一般的面向过程写法有些不一样,简单说就是它更抽象更简洁,而带来的副作用就是,代码比较难懂,执行效率也相对低一点。因此面向对象编程思想可分为两种,一种是函数式编程另外一种是命令式编程,它们的区别是:

函数式编程关心数据的映射,命令式编程关心解决问题的步骤。翻译成人话就是,函数式编程只负责处理数据的加工运算,不管代码逻辑结构,是一种更加抽象的方法。命令式编程就关注于代码逻辑结构,有时为了使代码结构更合理更易懂,我们不介意用非常臃肿的写法去完成一个运算目的。

python作为一门高级语言,自然也支持函数式编程,因为在python中一切皆是对象。可能有些朋友不知道对象是什么意思,前面讲过的那些变量就是对象,对象就是一个个在内存中拥有地址的变量。而函数,也是一种变量,在python中,由于函数也可以作为变量进行传递,所以python也支持函数式编程。

函数也是一个对象

要怎么理解函数也是一个对象呢,最好的办法就是通过代码认识一下。

def str_to_int(str_list): ''' 将字符类型的数字转换成整型 :param str_list: :return: ''' result = [] for item in str_list: result.append(int(item)) return resultdef get_total(str_to_int_func, list_1): ''' 对list_1求和 :param str_to_int: :param list_1: :return: ''' parse_list = str_to_int_func(list_1) return sum(parse_list)list_1 = [1, 2, 3, 4, 5]print(get_total(str_to_int, list_1))

上面我们首先定义了一个函数str_to_int,目的是用于将字符类型的数字转换成整型,然后定义一个求和函数,该函数接受一个字符串转换成整型的函数参数以及一个待求和的参数列表。最后我们定义一个带求和的列表,接着调用求和函数,但是我们仔细看一下,调用get_totoal函数的时候,我们传递了一个str_to_int对象,这个变量其实就是我们前面声明的函数,它也可以和一般变量一样作为参数传递给其它函数。当然这个例子没什么实际用处,实际也不会这么写,这里只是为了让大家明白,在python中,记住只是在python中,在其他语言不一定,函数也是一个对象,也是可以作为参数进行传递的。

知道了函数也是一个对象,可作为参数传递后,我们学习一下匿名函数。

lambda函数

匿名函数意思就是没有名字的函数,作为初学者可能会很奇怪,没有名字的函数?那怎么调用这个函数,不是没有名字么?接下来会为你解答。匿名函数由于没有名字,因此也不适用于涉及一大段的代码块,所以它又有另外一个说法,叫做一句话函数,就是说一条语句就可以写完的函数。

匿名函数的一般形式是:

lambda param1:expression

即lambda关键词+变量名称+冒号+表达式。表达式将会对参数进行运算并返回结果。

看个例子:

# 定义并调用一个匿名函数,该函数将对参数进行+1并将结果返回result = (lambda x: x + 1)(5)print(result)# 当然匿名函数也可以传递多个参数result = (lambda x, y: x + y)(5, 6)print(result)# 不止可以对数值变量进行计算,还可以对列表进行处理,下面的代码意思相当于result = [1,2,3,4,5] * 2result = (lambda x: x * 2)([1, 2, 3, 4, 5]) # 不要误认为会将列表的每个数都进行计算,实际上它是一个整体传进去的,即x=[1,2,3,4,5]print(result)

通过上面的例子我们知道怎么定义和调用匿名函数了,也应该明白,我们不应该让匿名函数做过多的事情,如果需要做过多的事情就要定义成普通函数。匿名函数适合那种一句话就可以完成的函数,这类函数定义成普通函数会过于臃肿,而定义成匿名函数则恰到好处。

接着解释一下匿名函数怎么调用的,上面的匿名函数是直接用括号括起来然后调用的,这样对于初学者来说不太好理解,我再这么写个例子就应该明白了:

# 定义并调用一个匿名函数,该函数将对参数进行+1并将结果返回my_func = lambda x: x + 1print(my_func(5))

这里我们把匿名函数赋值给一个变量,然后通过这个变量来调用匿名函数。就和普通函数一样,可以通过函数名称调用函数并传递值。

匿名函数真正的威力是和其它几个python的高阶函数结合使用,它们分别是map,reduce,filter,sorted。

map函数

map函数一般形式是:

map(func,seq)

其中func是一个函数变量,可以是普通函数也可以是匿名函数,seq是可迭代对象。关于什么是可迭代对象本章节不会讲,以后会有专门的章节讲,现在我们可以把可迭代对象当成list,dict这些复合类型就行。

map的实际使用:

# map调用普通函数def str_to_int(str_obj): return int(str_obj)result = map(str_to_int, ['1', '2', '3'])print(list(result))# map调用匿名函数result = map(lambda x: int(x), ['1', '2', '3'])print(list(result))# 可以传递多个参数result = map(lambda x, y: x + y, [1, 2, 3], [4, 5, 6])print(list(result))

输出结果:

[1, 2, 3][1, 2, 3][5, 7, 9]

要注意的是,map函数会将参数的每一项都拿出来传入给函数对象,而不是将参数作为一个整体传入。并且map返回的是一个惰性的迭代对象,所以如果我们要拿返回结果,应该用list计算一下。

另外,传递多个参数和一个参数的计算方式是不同的,为了方便理解,请看下图:

一个参数时,计算方式是这样的:

即将参数的每一项循环计算输出。

两个参数时,计算方式是这样的:

即将对应参数的对应项循环传递进行计算,比如上图的就是x=[1,2,3]、y=[4,5,6],接着循环对应项进行计算,先取第一项就是x[0]+y[0]就是1+4,如此循环。

reduce函数

reduce函数的一般形式和map一样也是:

reduce(func,seq)

不过值得注意的是,reduce在python3中被移植到了functools模块中,所以我们要先引入才能使用。reduce的计算思想比较难以用语言描述,不过reduce翻译成中文的意思就是合并。我们可以简单的理解为合并运算。下面通过代码来理解一下:

from functools import reduce# 相当于求和result = reduce(lambda x, y: x + y, [1, 2, 3])print(result)# 相当于连接字符串result = reduce(lambda x, y: x + y, ['I', ' Love', ' you'])print(result)

输出结果:

6I Love you

上述代码实现了两个功能,分别是求和和链接字符串。求和的计算过程翻译成图就是:

第一次先将列表的前两项传入给x,y,然后计算和返回,再接着取列表的下一项跟返回的和继续传入给x,y接着求和,如此循环。

filter函数

filter函数的形式跟map也是一样的,这里不再重复。这个函数比较好理解,它就是把符合条件的值都过滤出来并返回。

比如下面的代码就是将大于5的值都过滤出来返回:

result = filter(lambda x: x > 5, [2, 3, 5, 7, 8, 9])print(list(result))

输出结果:

[7, 8, 9]

我们可以用这个函数来做一些简单的过滤操作。

sorted函数

sorted是python内置的一个排序函数,使用它,就不需要我们去写排序算法了,而且它的使用非常灵活。废话不多说,直接看例子:

# 简单的对列表进行数字大小比较并升序输出result = sorted([23, 1, 34, 10])print(result)# 简单的对列表进行数字大小比较并倒序输出result = sorted([23, 1, 34, 10], reverse=True)print(result)# 不仅列表,我们也可以操作字典dict_1 = {'two': 2, 'four': 4, 'one': 1}# 按值排序result = sorted(dict_1.items(), key=lambda item: item[1])print(result)# 按键排序result = sorted(dict_1.items(), key=lambda item: item[0])print(result)

输出结果:

[1, 10, 23, 34][34, 23, 10, 1][('one', 1), ('two', 2), ('four', 4)][('four', 4), ('one', 1), ('two', 2)]

sorted函数的更多用法就需要你们自己取摸索,对于初学者来说,这些就够了。

函数式编程的利与弊

函数式编程有好的一面就有坏的一面,不是什么情况都适合用函数式编程的,况且python并不完全支持函数式编程的所有特性。关于函数式编程的利与弊,我结合前面的例子做一个综合的说明。假如我们要实现一个功能,需要先对数字字符进行转换为整型然后再求和,求和之后,如果结果比10大就返回,比10小就丢弃。这么一个功能如果用函数式来写的话就是:

from functools import reduceresult = filter(lambda x: x > 10, [reduce(lambda x, y: x + y, list(map(lambda x: int(x), ['4', '5', '6']))), reduce(lambda x, y: x + y, list(map(lambda x: int(x), ['1', '2', '3'])))])print(list(result))

这个函数给你第一眼感觉是什么?晕是吧。别说初学者,就是有经验的人,看到这样的写法都头疼,虽然很简短的代码就实现了这么多功能,但是代码阅读性太差了,即使是本人,过段时间回过头来,也未必知道自己写的是什么玩意。

如果我把它这样写呢:

def str_to_int(str_obj): return int(str_obj)def get_total(list_1): total = 0 for item in list_1: total += str_to_int(item) return totalresult_1 = get_total(['1', '2', '3'])result_2 = get_total(['4', '5', '6'])result = [result_1, result_2]print(list(filter(lambda x: x > 10, result)))

这样代码是不是好很多,虽然代码量多了,但是可阅读性高了,你好我好大家好。

我们在选择函数式编程的时候,切记不要混合使用,要易易懂为主,炫酷为次。python的函数式编程本质上是为了简短的普通函数服务的,并不适合功能复杂的函数。而且有些公司明确规定不然程序员写函数式编程,怕的就是以后你的代码没人看懂,不知道怎么修改。

好了,今天就到这里。

如果对我的文章感兴趣,可以关注我的主页也可以关注我的公众号:

(0)

相关推荐

  • typing库:让你的代码阅读者再也不用猜猜猜

    Python以其简洁的代码而闻名于世.除了缩进之外,代码样式和文档主要取决于编写应用程序的开发人员的习惯,这可能导致一些混乱,产生难以理解的代码.而这主要是因为Python是一种动态类型语言,请看以下 ...

  • 危险的转变:Python正在从简明转向臃肿,从实用转向媚俗

    作者 | 天元浪子 头图 | CSDN 出品 | CSDN 博客 国庆长假期间,Python3.9正式推出,各大IT平台和众多自媒体纷纷火力全开,热推Python3.9的新增特性.然而,除了媒体的自娱 ...

  • 25 条超棒的 Python 一行代码

    自从用Python编写第一行代码以来,就被它的简单性.出色的可读性和特别流行的一行代码所吸引. 在下面,我将给大家介绍并解释一些Python一行程序. 可能有些你还不知道,但对你未来的Python项目 ...

  • Python学习—函数

    刚开始学习Python函数的时候,觉得自己C语言用的很溜,Python函数应该没啥难度,结果越学越觉得自己就是孤陋寡闻,不明白的,一知半解的东西太多,觉得自己这几年完全荒废了,丧失了学习的劲头:还好在 ...

  • 一行 Python 代码实现并行,骚技能!

    当我用Python写第一行代码的那一天,我着迷于简单性,流行性及其著名的单行代码. 1.交换两个变量 # a = 4 b = 5a,b = b,a# print(a,b) >> 5,4 让 ...

  • Python高阶函数

    该篇中主要介绍什么是高阶函数,高阶函数的用法以及几个常见的内置的高阶函数. 什么是高阶函数? 高阶函数:一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身, ...

  • 安利5个Python高阶函数:lambda,Map,Filter,Itertools,Generat...

    任何编程语言的高级特征通常都是通过大量的使用经验才发现的.比如你在编写一个复杂的项目,并在 stackoverflow 上寻找某个问题的答案.然后你突然发现了一个非常优雅的解决方案,它使用了你从不知道 ...

  • 第 14 天:Python 高阶函数

    函数式编程现在逐渐被广大开发群体接受,越来越多的开发者们开始使用这种优雅的开发模式,而我们使用函数式编程最主要的是需要清楚: 什么是高阶函数(Higher-order Functions)? Pyth ...

  • Julia机器核心编程.高阶函数

    我这个起名好麻烦,都说函数完了.有整出来一个高阶函数,比较麻烦. 嵌套函数,简单来说,就是在函数中定义函数. 闭包是一个函数对象,它可以记住封闭范围中的值,即使它们不在内存中也是如此. 嵌套函数有助于 ...

  • 高阶函数

    高阶函数 函数柯里化 函数柯里化,又称部分求值.一个currying函数首先会接收一些参数,接受这些参数后该函数不会立即求值.而是会将传入的参数在函数内保存,待函数真正需要求值时,之前的所有参数都会被 ...

  • js 高阶函数reduce ——数组取交集、并集

    两个数组取交集 vs 多个数组取交集 => js reduce函数的妙用 1.reduce函数的用法及取数组交集 <script> // 值集数组 let arr1 = [1,2] ...

  • 如何去使用Python里面的函数式编程和闭包?

    对于开发者来说除了基础语法之外,一些比较常用的开发手段也是需要去学习和使用的.这里小千就来教大家如何去使用Python里面的函数式编程和闭包. 函数式编程 函数式编程这个概念我们可能或多或少都听说过, ...

  • Python中的函数式编程教程,学会用一行代码搞定所有内容

    https://m.toutiao.com/is/JEUURVQ/ 前言 在本文中,您将了解什么是函数范型,以及如何在Python中使用函数式编程.在Python中,函数式编程中的map和filter ...

  • 写 Python 代码不可不知的函数式编程技术

    2021-10-09 本文对 Python 中的函数式编程技术进行了简单的入门介绍. 近来,越来越多人使用函数式编程(functional programming).因此,很多传统的命令式语言(如 J ...