• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > 利用Fn.py库在Python中进行函数式编程

利用Fn.py库在Python中进行函数式编程

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了python函数式编程,函数式编程,函数式编程语言,javascript函数式编程,js函数式编程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

尽管Python事实上并不是一门纯函数式编程语言,但它本身是一门多范型语言,并给了你足够的自由利用函数式编程的便利。函数式风格有着各种理论与实际上的好处(你可以在Python的文档中找到这个列表):

  •     形式上可证
  •     模块性
  •     组合性
  •     易于调试及测试

虽然这份列表已经描述得够清楚了,但我还是很喜欢Michael O.Church在他的文章“函数式程序极少腐坏(Functional programs rarely rot)”中对函数式编程的优点所作的描述。我在PyCon UA 2012期间的讲座“Functional Programming with Python”中谈论了在Python中使用函数式方式的内容。我也提到,在你尝试在Python中编写可读同时又可维护的函数式代码时,你会很快发现诸多问题。

fn.py类库就是为了应对这些问题而诞生的。尽管它不可能解决所有问题,但对于希望从函数式编程方式中获取最大价值的开发者而言,它是一块“电池”,即使是在命令式方式占主导地位的程序中,也能够发挥作用。那么,它里面都有些什么呢?
Scala风格的Lambda定义

在Python中创建Lambda函数的语法非常冗长,来比较一下:

Python

map(lambda x: x*2, [1,2,3])

</div>

Scala

List(1,2,3).map(_*2)</div>

Clojure

(map #(* % 2) '(1 2 3))</div>

Haskell

map (2*) [1,2,3]</div>

受Scala的启发,Fn.py提供了一个特别的_对象以简化Lambda语法。

from fn import _

assert (_ + _)(10, 5) = 15
assert list(map(_ * 2, range(5))) == [0,2,4,6,8]
assert list(filter(_ < 10, [9,10,11])) == [9]

</div>

除此之外还有许多场景可以使用_:所有的算术操作、属性解析、方法调用及分片算法。如果你不确定你的函数具体会做些什么,你可以将结果打印出来:

from fn import _ 

print (_ + 2) # "(x1) => (x1 + 2)" 
print (_ + _ * _) # "(x1, x2, x3) => (x1 + (x2 * x3))"

</div>

流(Stream)及无限序列的声明

Scala风格的惰性求值(Lazy-evaluated)流。其基本思路是:对每个新元素“按需”取值,并在所创建的全部迭代中共享计算出的元素值。Stream对象支持<<操作符,代表在需要时将新元素推入其中。

惰性求值流对无限序列的处理是一个强大的抽象。我们来看看在函数式编程语言中如何计算一个斐波那契序列。

Haskell

Clojure

Scala

     0 #:: 1 #:: fibs.zip(fibs.tail).map{case (a,b) => a + b} </div>

现在你可以在Python中使用同样的方式了:

from fn import Stream 
from fn.iters import take, drop, map
from operator import add

f = Stream()
fib = f << [0, 1] << map(add, f, drop(1, f))

assert list(take(10, fib)) == [0,1,1,2,3,5,8,13,21,34]
assert fib[20] == 6765
assert list(fib[30:35]) == [832040,1346269,2178309,3524578,5702887]

</div>

蹦床(Trampolines)修饰符

fn.recur.tco是一个不需要大量栈空间分配就可以处理TCO的临时方案。让我们先从一个递归阶乘计算示例开始:

def fact(n):
   if n == 0: return 1
   return n * fact(n-1)

</div>

这种方式也能工作,但实现非常糟糕。为什么呢?因为它会递归式地保存之前的计算值以算出最终结果,因此消耗了大量的存储空间。如果你对一个很大的n值(超过了sys.getrecursionlimit()的值)执行这个函数,CPython就会以此方式失败中止:

>>> import sys
>>> fact(sys.getrecursionlimit() * 2)
... many many lines of stacktrace ...
RuntimeError: maximum recursion depth exceeded

</div>

这也是件好事,至少它避免了在你的代码中产生严重错误。

我们如何优化这个方案呢?答案很简单,只需改变函数以使用尾递归即可:

def fact(n, acc=1):
   if n == 0: return acc
   return fact(n-1, acc*n)

</div>

为什么这种方式更佳呢?因为你不需要保留之前的值以计算出最终结果。可以在Wikipedia上查看更多尾递归调用优化的内容。可是……Python的解释器会用和之前函数相同的方式执行这段函数,结果是你没得到任何优化。

fn.recur.tco为你提供了一种机制,使你可以使用“蹦床”方式获得一定的尾递归优化。同样的方式也使用在诸如Clojure语言中,主要思路是将函数调用序列转换为while循环。

from fn import recur

@recur.tco 
def fact(n, acc=1):
   if n == 0: return False, acc
   return True, (n-1, acc*n)

</div>

@recur.tco是一个修饰符,能将你的函数执行转为while循环并检验其输出内容:

  •     (False, result)代表运行完毕
  •     (True, args, kwargs)代表我们要继续调用函数并传递不同的参数
  •     (func, args, kwargs)代表在while循环中切换要执行的函数

函数式风格的错误处理

假设你有一个Request类,可以按照传入其中的参数名称得到对应的值。要想让其返回值格式为全大写、非空并且去除头尾空格的字符串,你需要这样写:

class Request(dict):
   def parameter(self, name):
     return self.get(name, None)

r = Request(testing="Fixed", empty=" ")
param = r.parameter("testing")
if param is None:
   fixed = ""
else:   
   param = param.strip()
   if len(param) == 0:
     fixed = ""
   else:
    fixed = param.upper() 

</div>

额,看上去有些古怪。用fn.monad.Option来修改你的代码吧,它代表了可选值,每个Option实例可代表一个Full或者Empty(这点也受到了Scala中Option的启发)。它为你编写长运算序列提供了简便的方法,并且去掉除了许多if/else语句块。

from operator import methodcaller
from fn.monad import optionable

class Request(dict):
   @optionable
   def parameter(self, name):
     return self.get(name, None)

r = Request(testing="Fixed", empty=" ")
fixed = r.parameter("testing") 
     .map(methodcaller("strip")) 
     .filter(len) 
     .map(methodcaller("upper")) 
     .get_or("")

</div>

fn.monad.Option.or_call是个便利的方法,它允许你进行多次调用尝试以完成计算。例如,你有一个Request类,它有type,mimetype和url等几个可选属性,你需要使用最少一个属性值以分析它的“request类型”:




 

您可能想查找下面的文章:

  • 总结Python编程中函数的使用要点
  • Python函数式编程指南(四):生成器详解
  • Python函数式编程指南(三):迭代器详解
  • Python函数式编程指南(二):从函数开始
  • Python函数式编程指南(一):函数式编程概述
  • 利用Fn.py库在Python中进行函数式编程
  • 用Python进行基础的函数式编程的教程
  • Python装饰器的函数式编程详解

相关文章

  • Python语言的12个基础知识点小结
  • Python下载懒人图库JavaScript特效
  • 从零学python系列之新版本导入httplib模块报ImportError解决方案
  • Python标准库urllib2的一些使用细节总结
  • 详谈Python2.6和Python3.0中对除法操作的异同
  • python3中dict(字典)的使用方法示例
  • Python常见文件操作的函数示例代码
  • Python模块学习 filecmp 文件比较
  • 使用IPython来操作Docker容器的入门指引
  • python实现爬虫下载漫画示例

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • 详解python进行mp3格式判断
    • Windows系统下安装Python的SSH模块教程
    • python抓取并保存html页面时乱码问题的解决方法
    • Python中的ceil()方法使用教程
    • python3音乐播放器简单实现代码
    • Python正则表达式如何进行字符串替换实例
    • 讲解Python的Scrapy爬虫框架使用代理进行采集的方法
    • 利用pyinstaller或virtualenv将python程序打包详解
    • python实现排序算法
    • python基础教程之popen函数操作其它程序的输入和输出示例

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有