初探函数式编程

前言

继续向下看廖大教程,看到了函数式编程这一节,当时是觉得没啥用直接跳过了,这次准备要仔细看一遍了,并记录下一些心得。

函数式编程

上学期有上一门叫 ‘人工智能’ 的课,老师强行要我们学了一个叫做 prolog 的语言,哇那感觉确实难受,思维方式完全和之前学过的不一样,写个汉诺塔想了半天,最后还是在网上找了段代码修改一下(怕被老师发现抄袭)才写出来,贴一段出来感受一下:

当时是差不多弄懂了,主要是资料实在太少,debug 都无从谈起,一遇上 bug 就 gg,我现在自己看也有点头晕。不过据说 prolog 当年能和 Lisp 一争高下,最近对 Lisp 也有点兴趣,等弄完这些就去参拜一下这类函数式语言。

何谓函数式编程?廖大这里写道:

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

可能看完还是有些不太理解,不急,先看完这几个小节吧。

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入
  • 输出一个函数

也就是说,把函数本身当成参数传递,或者返回一个函数。

例如,可以像普通赋值一样将函数赋值给变量:

也可以给函数赋值(代码接上):

还可以传参,例如,一个计算所有数字的和的函数:

当然,将这个 f 换成乘法就是计算所有数字的乘积了。

再来看看 python 内置的一些高阶函数,经常会用到。

map/reduce

记得上学期上云计算的课程时依稀有听到过这个词,不过这课很水,就没怎么听,在这里看到好像发现不太一样??

不过没啥说的,简单说一下每个函数的作用。

对于 map,其计算式可以看成这样:

对于 reduce,其计算式可以看成这样:

廖大那里说得很清楚啦。

filter

filter 和 map 函数类似,接受一个函数和 iterable,返回也是一个 list,不过其功能是根据函数返回值是否为 True 来判断是否保留该值。例如:

sorted

sorted 函数同样是一个高阶函数,对参数 key 传递函数可以将需要排列的序列经过 key 函数处理后再进行排序,不过不会改变序列的值,例如:

装饰器(decorator)

匿名函数就不说了,以后用时再仔细看吧,装饰器我记得之前看 flask 的时候都研究了好久,这次再来复习一下。

简单装饰器

首先是一个简单的装饰器,在每次调用函数前打印出日志:

这就是一个极其简单的装饰器,如何使用它呢?我最先看到的用法是在需要装饰的函数前添加@,但其实这是 Python 的一个语法糖,最原始的用法反而更能让人理解,先定义一个函数 f:

这样定义了之后,我们再调用 f 函数:

使用 @log 的结果与其一样,其实@符号作为装饰器的语法糖,与前面的赋值语句具有相同的功能,使代码看起来更简洁明了,避免再一次赋值操作,就像下面这样:

含参数的装饰器

有时候我们还需要向装饰器中传入参数,例如,状态,层次等信息,只需要在 wrapper 函数外再’包裹’一层函数,如下所示:

进一步理解

为了再进一步理解装饰器,我们可以打印出函数 f 的 name 属性:

联系到最前面的装饰器赋值语句,就可以大致明白发生了什么:f = log(f) 使得 f 指向修改为 log(f) 的返回值,即 wrapper 函数。每次运行原函数 f 时,则会调用 wrapper 函数,在我们这个例子中,则是先打印日志,然后运行原函数 f。

不过这样有一个问题,这样使得原函数 f 的元信息被替换了,关于 f 的许多信息消失不见,这是很难令人接受的,不过好在我们有 functools 模块,修改函数为:

另外,还可以对同一个函数添加多个装饰器:

总结

关于函数式编程我也不是很了解,这里只是大概了解了一下其概念吧,平时肯定还是使用命令式编程用得多。不过有语言是纯函数式语言,例如 Haskell 或 Lisp,学习它们会使得人打开一种新思路。

以上~

1 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部