演讲者:丁来强@Splunk  PyConChina2015 北京站

9月12日与9月19日,PyConChina 2015上海站与北京站顺利落下帷幕。“人生苦短,Python 当歌”是本届的主题。 在PyCon北京场,Splunk的Tech Lead丁来强为大家带来了两场干货满满的技术分享,收获了业内无数好评。

关于函数式编程

有哪些函数式语言?

其实函数是语言很早就出现了,上世纪30年代出现的Lambda和50年代的LISP,比面向过程和对象的语言出现的更早,现代的Clojure,Erlang,Haskeel也为很多人所熟知,保持着很强的活力,Scala作为Spark和Kafka的实现语言也是相当的火。

什么是函数式语言?

和面向过程的编程语言(例如C等)和面向对象的语言(例如C++/Java等)相比,函数式语言是一种声明式的编程规约范式。 简单例子如下:

一个复杂些的例子:

计算如下字符串的值:expr = "28+32+++32++39” ==> 28+32+32+39 ==> 131

命令式的语言采用一个初始值,然后一直去是修改它,最终获得结果。

而函数式风格通过函数的组合调用,通过函数的一层层转换输入输出最终获得结果。

作为一种风格,很多人的代码里面可能已经有一些是函数式的了。

函数式编程的特点

函数式编程有如下特点:函数即为数据,第一等公民

高阶函数

纯函数: 避免状态,无副作用

不可变数据结构

强编译器

尾递归消除(TRE)

延迟,模式匹配(Pattern Match),Monads

这个议题除了Monads,其他都有所覆盖。

回到Python,Python其实是一个具备了很强函数式能力的命令式编程语言,通过语言或者库的支持,对以上几乎所有特征都有所支持(除了强编译器)。

一些函数语言编译执行器可以在强预设下做很强的优化,例如直接并发,延迟处理或者次序调换等。 而Python却没有这一点支持,归根结底是因为Python从一开始就是按照命令式语言进行设计的。 Guido大叔曾经说过这样一段话:

"I have never considered Python to be heavily influenced by functional languages, ... I had made functions first-class objects, I didn't view Python as a functional programming language..."

尽管如此,函数式编程风格依然是一种非常不错的风格。 主要有几个原因:

更好的测试性(因为无状态),也更可靠

更擅长流式与并发操作(例如Scala)

一些偏主观的观点: 例如函数式编程风格有的时候提供了一种更加简洁巧妙的解决方案。 代码更少,可读性更好。

纯函数第一等公民就像Guido所说,Python中的函数已经是第一等公民了。皆可以作为变量,也可以作为参数传入传出,也可以随时Lambda定义,或者放入数据,所有操作符也都是已经函数化的了。

通过fn库,函数定义的方式可以进一步简化为Scala风格:

纯函数

无副作用

无副作用体现在对输入的数据本身无修改,对函数内部外部无状态修改。

如下的例子都是一些反例。

修改了输入

修改了外界状态

修改了输出,影响了原输入

真正纯的无状态和副作用的函数应该如下:

但是这可能比较复杂,性能也不太好。 这就要引入函数编程里的可持久化数据结构。

可持久化数据结构一种支持修改,在不修改原版本的情况下,返回一个修改版本的数据结构。

Persistent Data

高阶函数

高阶函数就是接受或者返回函数的函数。

Python已有不错的支持:map,filter,groupby,reduce

functools module

list comprehension

decorators

Mapmap是函数式编程语言中很重要的高阶函数,接受函数对输入进行转换。

Filter

reduce接受函数对输入进行过滤。

List Comprehension

Map/Filter在函数式编程中非常重要,然后Python里面list Comprehension可能适用的更加广泛,过滤转换,最终构造出list,set,dict等都非常简单。

然而List Comprehension一些特性也需要注意,首先是第一层才是不可修改的,对于初学者而言,读取方式也稍微奇怪(先for,再if,最后看开头),另外内部存在for/if,并没有函数模块化。

GroupbyGroupby接受函数对数据进行分组:

ReduceReduce接受二元函数对数据进行聚集:

Reduce的实现可以理解为如下:

相对应的sum,mul也可以直接使用reduce来完成

Partial

首先一个简单问题,如何构造一个默认是降序排列的Sorted2函数,如下:

一般的实现:

而使用Partial则简单的多。

Partial还可以用来预先参数绑定。 例如:

ComposeCompose是常用来构建更高级函数的工具:

CurryingCurrying是对Partial的更进一步的扩展:

toolz.curried里面所有的函数都已经Curry化了。

Currying对于简化参数化Decorator也是非常有用的。 例如:

递归相关技术

关于递归

一些函数式语言里面没有loop,只能用递归。 而通常都支持尾递归消除(将递归转化为内部loop)

用递归的理由

代码逻辑更清晰。例如:

不用递归的原因三个原因使得递归没有大量被使用,因为:递归调用有递归层数限制(Python是1000),超过会栈溢出。

重复计算。 fib(n-2)与fib(n-1)是存在重复计算的。

递归调用常常需要不同情况进行跳转,需要大量使用overloading或者pattern match的技术。

关于尾递归消除(优化)尾递归优化可以消除递归层数的限制,要求递归只存在于函数调用的最后一行,并且没有进一步计算。

如下是反例:

通常使用一个帮助函数,将计算放在计算放在参数传递时,是常用技巧:

Trampoline然而坏消息是: Python并不支持尾递归消除!(Guido: 怪我咯!)

但并不用担心,Tranpline就是用来解决这个问题的。 添加fn.recur的decorator,对于要结束递归的分支,返回False开头的tuple,否则返回True开头的tuple即可。

消除重复计算Python自带的lru_cache即可消除重复计算的问题:

另外推荐(cy)toolz里面的memoize,支持更多功能,例如cache可以让代码更简洁。

支持重载Python语言本身是不支持函数重载的,但其语言自身函数功能也很强大:未命名参数,命名参数,变参,命名变参,解包机制等。

让Python支持类似于C++/Java等里面的重载,只需要引入multipledispatch.dsipatch即可,需要注意一开始的初始化。

重载使得递归的逻辑更加简洁

Haskell类强大的pattern match功能不仅支持类型重载,也支持参数特征匹配。 这在Python中通过库也是支持的。 至于实现机制,有兴趣的朋友可以看一下Python AST。

延迟遍历器带来的延迟计算是Python核心惯用法。 常见的例子有:xrange

tuple comprehension

itertools 模块

dict.iter* 方法

generator

for-loop 协议

fn.Stream提供了进一步的语法糖,例如给跌代添加切片功能。

Generator对于实现无限迭代器是很方便的。

fn.Stream也支持通过流方式来实现。

更多迭代器可以在(cy)toolz.itertoolz中可以找到:统计: count,groupby,frequency

过滤: unique,partition

选择: take,drop,first,last,n_th etc。

merge_sorted

并行

值得一提的是函数式编程天生就是支持并行的。

Map因为传递的函数是无状态无副作用的,所以可以直接并发执行,加快执行效率。

Reduce同理,Reduce也是可以并发执行来进行二元聚集最终实现Log级别的性能优化。

Python多进程与分布式策略算法大师Knuth说过:"97%过早优化是罪恶之源",在选择多进程或者分布式的时候考虑是否是唯一选择。 可能的其他选项有:

选择不同的Python解释器: Cython,PyPy,numba等

某些情况下分布式增加的管理复杂度不如单点增加多核来的有效。

通过GPU提高计算效率是数据科学领域的一个趋势。

IO密集型并一定普遍适用于增加多进程的情况。

Python并发选择GIL的原因,计算密集型是的多线程没有意义。

Python自带multiprocessing库提供了很不错的高阶接口。

分布式通用领域计算模型的选择有Spark,Hadoop,Celery等对于数据科学方面,分布式numpy和全局数据矩阵发展的也非常快。

Python并发分布式库可较为成熟,供选择的也很多:自带的Multiprocessing/RPC库

IPython Cluster

scikit-learn 并行算法

Python Parallel(只有Py2),Celery

更多: joblib等

并发计算与数据分发并行计算只需要替换现有默认函数为并发函数即可。 例如Pool.map取代模块的map。

然而并发与分布式计算需要考虑如何把数据传入传出模块,一般的数据都是可以的。 然而Closure默认不能pickle化,这种情况下需要使用copy_reg扩展或者使用dill库。

IPython Cluster因为使用dill库,并不存在这个问题。

如下图是自带多进程库,IPython Cluster与Celery的一个比较,其中橙色勾表示需要一些额外代码来支持,叉表示需要较多额外工作支持。

总结

通过来强深入浅出的介绍,大家了解了如何使用Python进行高逼格函数式编程的技术,工具和实践。 使用Python也可以享受函数编程所带来的高模块,可复用,并发流处理等方面的好处。

python partition函数_如何使用正确的姿势进行高效Python函数式编程?相关推荐

  1. python log函数_求你别再花大价钱学 Python 之爬虫实战

    引子 Python 基本概念 Python 优势和劣势 优势 Python 的劣势 Python 安装设置 Python 基本语法 程序例子 Python 基本语法 Python 爬虫实现 爬虫相关 ...

  2. python partition函数_在Python中相当于R的createDataPartition

    在scikit learn中,您将获得工具train_test_splitfrom sklearn.cross_validation import train_test_split from skle ...

  3. python len函数_你需要了解的最重要的Python概念

    了解有关Python语言构建模块的所有信息 > Image by author Python很容易学习. 但是,它具有某些难以理解的方面,例如类和对象的世界. 在本文中,您将学习: · 在Pyt ...

  4. python random函数_详细代码实战讲解:如何用 Python让自己变成天选之子

    今天为大家带来的内容是:详细代码讲解:如何用 Python让自己变成天选之子 话不多说直接上代码: 请大家猜一猜下面这段代码的运行效果: 你是不是以为这段代码运行以后,结果如下图所示? 但实际上,我可 ...

  5. python partition函数_Python partition()函数的使用方法

    Python中 partition() 函数的作用是在首次出现分隔字符串的位置把字符串分割为三部分,并以元组的形式返回分割结果,返回的元组中包括分隔字符串之前的部分,分隔字符串本身及分隔字符串之后的部 ...

  6. python编写函数_浅谈Python 函数式编程

    匿名函数lambda表达式 什么是匿名函数? 匿名函数,顾名思义就是没有名字的函数,在程序中不用使用 def 进行定义,可以直接使用 lambda 关键字编写简单的代码逻辑.lambda 本质上是一个 ...

  7. python pos函数_使用python+sklearn实现特征提取

    sklearn.feature_extraction模块可用于以机器学习算法支持的格式从原始数据集(如文本和图像)中提取特征.**注意:**特征提取与特征选择有很大不同:前者是将任意数据(例如文本或图 ...

  8. python deepcopy函数_用Python解数独[6]:递归获得最终答案

    目录 用Python解数独[0] 用Python解数独[1]:求每个单元格的行值域 用Python解数独[2]:求列值域和九宫格值域 用Python解数独[3]:求总值域 用Python解数独[4]: ...

  9. python len函数_知识清单Python必备的69个函数,你掌握了吗?

    本文纲要 Python 作为一门高级编程语言,为我们提供了许多方便易用的内置函数,节省了不少开发应用的时间.目前,Python 3.7 共有 69 个内置函数,一些是我们耳熟能详的函数,另一些却不是很 ...

最新文章

  1. 10-19政治单选-多选答案
  2. Quartz.net持久化与集群部署开发详解
  3. 动态规划 dp02 最长非降子序列问题 c代码
  4. POJ 1017 Packets【贪心】
  5. 性能测试培训:定位jvm耗时函数
  6. java中gc是怎么工作的_java中的GC(gabage collection)如何工作
  7. BCVP开发者说第5期:QuartzCore.Blazor
  8. MongoDB 自动删除集合中过期的数据——TTL索引
  9. iOS 两个tableview的 瀑布流
  10. Android获取手机联系人或通讯录的基本信息(如姓名、电话)
  11. 基于live555的视频直播 DM368IPNC RTSP分析
  12. leetcode - 22. 括号生成
  13. 在Sping Boot logback的使用
  14. 最好的虚拟服务器,最好虚拟主机推荐给大家
  15. 游戏盾 > 产品简介 > 产品优势
  16. 持续集成部署Jenkins工作笔记0003---Web工程部署方式说明
  17. 为什么世界上近60%的人使用谷歌Chrome浏览器?
  18. 【安全科普】AD域安全管理(一)
  19. Unity3d学习之路-简单打飞碟小游戏
  20. 华为交换机初始化_华为交换机初始设置

热门文章

  1. 让后台服务不被杀———电话录音
  2. 总结一下一般游戏中3D模型各种勾边方法遇到的工程性问题
  3. PB_Truncate函数截取小数点引起的数字错误
  4. STM32单片机,禁止系统启动时的变量初始化
  5. 蓝牙协议分析_BLE地址类型
  6. TCP/IP总结(4)TCP 概述
  7. C++ Primer 5th笔记(chap 19 特殊工具与技术)使用 RTTI
  8. 区块链BaaS云服务(22)趣链BitXHub跨链平台
  9. 进程间通信(1) dll 实现进程的内存共享
  10. 初等数论--整除--带余除法