原标题:写 Python 代码不可不知的函数式编程技术

选自 Medium

作者:Raivat Shah

参与:魔王、Jamin

本文对 Python 中的函数式编程技术进行了简单的入门介绍。

近来,越来越多人使用函数式编程(functional programming)。因此,很多传统的命令式语言(如 Java 和 Python)开始支持函数式编程技术。本文对 Python 中的函数式编程技术进行了简单的入门介绍。

本文适合对函数式编程有基本了解的读者。如果你对函数式编程并不熟悉,可以先阅读这篇文章:https://medium.com/@yannickdot/functional-programming-101-6bc132674ec5。

本文作者是新加坡国立大学计算机学院和「USP」博学计划学生 Raivat Shah,专注于编程与数据研究。

头等函数

在 Python 中,函数是「头等公民」(first-class)。也就是说,函数与其他数据类型(如 int)处于平等地位。

因而,我们可以将函数赋值给变量,也可以将其作为参数传入其他函数,将它们存储在其他数据结构(如 dicts)中,并将它们作为其他函数的返回值。

把函数作为对象

由于其他数据类型(如 string、list 和 int)都是对象,那么函数也是 Python 中的对象。我们来看示例函数 foo,它将自己的名称打印出来:

deffoo:

print( "foo")

由于函数是对象,因此我们可以将函数 foo 赋值给任意变量,然后调用该变量。例如,我们可以将函数赋值给变量 bar:

bar = foo

bar

#will print "foo" to the console

语句 bar = foo 将函数 foo 引用的对象赋值给变量 bar。

把对象作为函数

当对象可调用时(callable),它们与函数一样,如 object。这是通过 __call__ 方法实现的。

示例如下:

classGreeter:

def__init__( self, greeting):

self.greeting = greeting

def__call__( self, name):

returnself.greeting + " "+ name

每一次配置 Greeter 类的对象时,我们都会创建一个新的对象,即打招呼时可以喊的新名字。如下所示:

morning = Greeter( "good morning") #creates the callable object

morning( "john") # calling the object

#prints "good morning john" to the console

我们可以调用 morning 对象的原因在于,我们已经在类定义中使用了 __call__ 方法。为了检查对象是否可调用,我们使用内置函数 callable:

callable(morning) # true

callable( 145) # false. intisnotcallable.

数据结构内的函数

函数和其他对象一样,可以存储在数据结构内部。例如,我们可以创建 int to func 的字典。当 int 是待执行步骤的简写时,这就会派上用场。

# store in dictionary

mapping = {

0 : foo,

1 : bar

}

x = input #get integer value from user

mapping[ x] #call the func returned by dictionary access

类似地,函数也可以存储在多种其他数据结构中。

把函数作为参数和返回值

函数还可以作为其他函数的参数和返回值。接受函数作为输入或返回函数的函数叫做高阶函数,它是函数式编程的重要组成部分。

高阶函数具备强大的能力。就像《Eloquent Java》中解释的那样:

「高阶函数允许我们对动作执行抽象,而不只是抽象数值。」

我们来看一个例子。假设我们想对一个项目列表(list of items)执行迭代,并将其顺序打印出来。我们可以轻松构建一个 iterate 函数:

defiterate(list_of_items):

foritem inlist_of_items:

print(item)

看起来很酷吧,但这只不过是一级抽象而已。如果我们想在对列表执行迭代时进行打印以外的其他操作要怎么做呢?

这就是高阶函数存在的意义。我们可以创建函数 iterate_custom,待执行迭代的列表和要对每个项应用的函数都是 iterate_custom 函数的输入:

defiterate_custom(list_of_items, custom_func):

foritem inlist_of_items:

custom_func(item)

这看起来微不足道,但其实非常强大。

我们已经把抽象的级别提高了一层,使代码具备更强的可重用性。现在,我们不仅可以在打印列表时调用该函数,还可以对涉及序列迭代的列表执行任意操作。

函数还能被返回,从而使事情变得更加简单。就像我们在 dict 中存储函数一样,我们还可以将函数作为控制语句,来决定适合的函数。例如:

defadd(x, y):

returnx + y

defsub(x, y):

returnx - y

defmult(x, y):

returnx * y

defcalculator(opcode):

ifopcode == 1:

returnadd

elifopcode == 2:

returnsub

else:

returnmult

my_calc = calculator( 2) #my calc is a subtractor

my_calc( 5, 4) #returns 5 - 4 = 1

my_calc = calculator( 9) #my calc is now a multiplier

my_calc( 5, 4) #returns 5 x 4 = 20.

嵌套函数

函数还可以在其他函数内部,这就是「内部函数」。内部函数在创建辅助函数时非常有用,辅助函数即作为子模块来支持主函数的小型可重用函数。

在问题需要特定函数定义(参数类型或顺序)时,我们可以使用辅助函数。这种不遵循传统做法的操作使得解决问题变得更加简单,示例参见:http://www-inst.eecs.berkeley.edu/~cs61a/sp12/lectures/lect4-2x3.pdf。

假设你想定义一个斐波那契函数 fib(n),该函数只有一个参数 n,我们必须返回第 n 个斐波那契数。

定义此类函数的一种可行方式是:使用辅助函数来追踪斐波那契数列的前两个项(因为斐波那契数是前两个数之和)。

deffib(n):

deffib_helper(fk1, fk, k):

ifn == k:

returnfk

else:

returnfib_helper(fk, fk1+fk, k+ 1)

ifn <= 1:

returnn

else:

returnfib_helper( 0, 1, 1)

将该计算从函数主体移到函数参数,这具备非常强大的力量。因为它减少了递归方法中可能出现的冗余计算。

单表达式函数(Lambda 表达式)

如果我们想在未给函数命名之前写一个函数要怎么做?如果我们想写一个简短的单行函数(如上述示例中的函数 foo 或 mult)要怎么做?

我们可以在 Python 中使用 lambda 关键字来定义此类函数。示例如下:

mult = lambda x, y: x * y

mult(1, 2) #returns 2

该 mult 函数的行为与使用传统 def 关键字定义函数的行为相同。

注意:lambda 函数必须为单行,且不能包含程序员写的返回语句。

事实上,它们通常具备隐式的返回语句(在上面的示例中,函数想表达 return x * y,不过我们省略了 lambda 函数中的显式返回语句)。

lambda 函数更加强大和精准,因为我们还可以构建匿名函数(即没有名称的函数):

( lambdax, y: x * y)( 9, 10) #returns 90

当我们只需要一次性使用某函数时,这种方法非常方便。例如,当我们想填充字典时:

import collections

pre_fill = collections.defaultdict(lambda: (0, 0))

#all dictionary keys and values are set to 0

接下来我们来看 Map、Filter 和 Reduce,以更多地了解 lambda。

Map、Filter 和 Reduce

Map

map 函数基于指定过程(函数)将输入集转换为另一个集合。这类似于上文提到的 iterate_custom 函数。例如:

def multiply_by_four(x):

return x * 4

scores = [3, 6, 8, 3, 5, 7]

modified_scores = list(map(multiply_by_four, scores))

#modified scores is now [12, 24, 32, 12, 20, 28]

在 Python 3 中,map 函数返回的 map 对象可被类型转换为 list,以方便使用。现在,我们无需显式地定义 multiply_by_four 函数,而是定义 lambda 表达式:

modified_scores = list( map(lambda x: 4* x, scores))

当我们想对集合内的所有值执行某项操作时,map 函数很有用。

Filter

就像名称所显示的那样,filter 函数可以帮助筛除不想要的项。例如,我们想要去除 scores 中的奇数,那么我们可以使用 filter:

even_scores = list(filter(lambda x: Trueif(x % 2== 0) elseFalse, scores))

#even_scores = [6, 8]

由于提供给 filter 的函数是逐个决定是否接受每一个项的,因此该函数必须返回 bool 值,且该函数必须是一元函数(即只使用一个输入参数)。

Reduce

reduce 函数用于「总结」或「概述」数据集。例如,如果我们想要计算所有分数的总和,就可以使用 reduce:

sum_scores= reduce((lambda x, y: x + y), scores)

#sum_scores = 32

这要比写循环语句简单多了。注意:提供给 reduce 的函数需要两个参数:一个表示正在接受检查的项,另一个表示所用运算的累积结果。

本文是关于函数式编程的一篇入门文章,虽然尽量完备地介绍了相关的知识,但并不是那么深入。如想了解更多,大家可以阅读以下资源:

Best Practices for Using Functional Programming in Python: https://kite.com/blog/python/functional-programming/

Functional Programming Tutorials and Notes: https://www.hackerearth.com/zh/practice/python/functional-programming/functional-programming-1/tutorial/

原文链接:https://medium.com/better-programming/introduction-to-functional-programming-in-python-3d26cd9cbfd7

号主是非科班进微软的资深工程师关注就无套路送你一份BAT算法大礼包。返回搜狐,查看更多

责任编辑:

python函数式编程读取数据时出现错误_写 Python 代码不可不知的函数式编程技术...相关推荐

  1. python存储和读取数据时出现错误_python读取json文件存sql及codecs读取大文件问题...

    preface: 最近帮师兄处理json文件,需要读到数据库里面,以备其后续从数据库读取数据.数据是关于yelp网站里面的: https://github.com/Yelp/dataset-examp ...

  2. python如何读取数据时出现错误_在python3中,关于redis读取数据带有‘b’的问题...

    在python3中,关于redis读取数据带有'b'的问题 #encoding=utf-8 from redis import * #读取数据 d1=input("您输入的数据是:" ...

  3. python函数式编程读取数据时出现错误_Python编程中,函数遇到问题是抛出错误好还是约定返回值好?...

    这其实是一个编码规范的问题,没有任何场景都适用的解决方案,就好比有了 list,但是还是需要 tuple,所以对于抛出异常好,还是返回值好,是需要具体情况看的. 在 C 语言中,通用的做法是函数返回一 ...

  4. python如何读取数据时出现错误_连接数据库时出现的错误,怎样解决??

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Traceback (most recent call last): File "src\pymssql.pyx", line 636 ...

  5. python逐行读取数据时出现错误_python如何逐行读取数据

    在实际开发的过程中,文件读写也很重要,下面说一下python如何逐行读取文件. 如果程序要读取行,通常只能用文本方式来读取,道理很简单,只有文本文件才有行的概念,二进制文件没有所谓行的概念. 文件对象 ...

  6. python从文件中读取数据时出现错误_Python 从文件中读取数据

    读取整个文件 # 案例:读取整个文件 # pi_digits.txt 3.1415926535 8979323846 2643383279 # file_reader.py with open ('p ...

  7. python逐行读取数据时出现错误_Python利用逐行读取readline()打印出现空行的解决办法...

    Python Python开发 Python语言 Python利用逐行读取readline()打印出现空行的解决办法 在利用readline()进行逐行读取文件的时候,我们一般使用以下程序: f=op ...

  8. python如何读取数据时出现错误_python读取excel数据报xlrd.biffh.XLRDError错误原因,,比如说我要读取 http...

    python读取excel数据报xlrd.biffh.XLRDError错误原因,,比如说我要读取 http 比如说我要读取 http://basic.10jqka.com.cn/600383/xls ...

  9. python从文件中读取数据时出现错误_python-从文件中读取数据

    一.读取整个文件 learnFile.py 绝对路径 #coding=UTF-8 importsys reload(sys) with open(r'C:\Users\zhujiachun\Deskt ...

最新文章

  1. python numpy.linspace() 使用介绍
  2. C 怎么读取Cpp文件_从PCD文件写入和读取点云数据
  3. 阿里重磅开源首款自研科学计算引擎Mars,揭秘超大规模科学计算
  4. xunit-ICollectionFixture
  5. vue 防止按钮重复点击
  6. RS请求错误之RSV-BBP-0028
  7. QByteArray与char、int、float(及其数组)之间的互相转化
  8. 王者荣耀钓鱼网源码php,王者荣耀钓鱼页面
  9. 学python数据分析心得体会800字_学习 Python 数据分析的正确姿势
  10. 怎么做名片二维码?个人二维码名片在线制作方法
  11. 在线QQ客服链接,只添加 qq号
  12. 【Python】Marshmallow:Python中的“棉花糖”
  13. 《萌小甜动图字帖》使用简介
  14. 如何将docx文本转换成使用微信小程序rich-text能编译的格式
  15. 加入美团2021届北斗计划,用科技定义未来生活
  16. cad注释比例和打印比例不一样_CAD注释性比例该如何设置?看完你就懂了
  17. 【Linux进程间通信】四、mmap共享存储映射
  18. C语言实现来实现字符串反转,只有单词顺序反转,组成单词的字母不反转
  19. 用HTML5实现手机摇一摇的功能并配上声音
  20. 实验 基本交换机设置

热门文章

  1. CodeSmith基础(七)
  2. 用二分类神经网络估算多分类神经网络迭代次数的经验公式
  3. 机器学习面试知识点汇总(Machine Learning Core Concepts Collection)
  4. 计算机考研我该如何准备,计算机考研该如何准备呢-考研初试
  5. 安徽师范大学计算机专业导师,安徽师范大学数学计算机科学学院导师介绍:罗永龙...
  6. flutter加载本地html标签,Flutter中如何加载并预览本地的html文件的方法
  7. 1.6 语言模型和序列生成-深度学习第五课《序列模型》-Stanford吴恩达教授
  8. 4.1 什么是人脸识别-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
  9. FPGA自定义UART传输(包含:matlab数据拆分)
  10. 【任务脚本】0528京东618叠蛋糕任务脚本全自动脚本,京东任务全自动程序稳定运行,向大神致敬...