为什么要使用 Python 进行函数式编程?

2024-05-05

在工作中,我们过去常常以非常标准的面向对象方式来编写 Python 程序。最近,有几个人加入了功能性潮流。他们的代码现在包含更多的 lambda、map 和reduce。我知道函数式语言有利于并发性,但是函数式 Python 编程真的有助于并发性吗?我只是想了解如果我开始使用更多 Python 的功能特性,我会得到什么。


Edit:我在评论中因为没有提供更多的解释/示例而受到批评(看起来部分是由 Python 中的 FP 狂热者引起的,但不完全是),因此,扩展答案以提供一些。

lambda, 更是如此map (and filter), and最特别的是reduce,几乎都不是 Python 中这项工作的正确工具,Python 是一种强大的多范式语言。

lambda与普通相比的主要优点(?)def声明是它使匿名的函数,同时def给函数一个名字——为了这个非常可疑的优势,你付出了巨大的代价(函数的主体仅限于一个表达式,生成的函数对象不可pickle,缺乏名称有时会使理解一个函数变得更加困难)堆栈跟踪或以其他方式调试问题 - 我需要继续吗?!-)。

考虑一下您有时在“Python”中看到的最愚蠢的习惯用法是什么(Python 带有“恐吓引号”,因为它显然是not惯用的Python——这是从惯用的Scheme或类似语言的一个糟糕的音译,就像Python中更频繁地过度使用OOP是从Java或类似的语言的一个糟糕的音译一样):

inc = lambda x: x + 1

通过为 lambda 分配一个名称,这种方法立即抛弃了上述“优点”——并且不会失去任何缺点!例如,incknow其名称 -inc.__name__是无用的字符串'<lambda>'-- 祝你好运,了解其中的一些堆栈跟踪;-)。当然,在这个简单的例子中实现所需语义的正确 Python 方法是:

def inc(x): return x + 1

Now inc.__name__是字符串'inc',显然应该如此,并且该对象是可腌制的 - 语义在其他方面是相同的(在这个简单的情况下,所需的功能可以轻松地适合一个简单的表达式 -def如果您需要临时或永久插入诸如以下之类的语句,那么重构也变得非常容易print or raise, 当然)。

lambda是一个表达式(的一部分),而def是一个语句(的一部分)——这是让人们使用的一点语法糖lambda有时。许多 FP 爱好者(就像许多 OOP 和过程式爱好者一样)不喜欢 Python 在表达式和语句之间相当强烈的区别(这是对 Python 的总体立场的一部分)命令查询分离 http://en.wikipedia.org/wiki/Command-query_separation)。我,我认为当你使用一种语言时,你最好“顺其自然”地使用它——就像它本来的样子designed被利用——而不是与之对抗;所以我用Pythonic方式编程Python,用Schematic (;-)方式编程Scheme,用Fortesque (?)方式编程Fortran,等等:-)。

继续到reduce——一条评论声称reduce是计算列表乘积的最佳方法。哦真的吗?让我们来看看...:

$ python -mtimeit -s'L=range(12,52)' 'reduce(lambda x,y: x*y, L, 1)'
100000 loops, best of 3: 18.3 usec per loop
$ python -mtimeit -s'L=range(12,52)' 'p=1' 'for x in L: p*=x'
100000 loops, best of 3: 10.5 usec per loop

因此,简单、基本、琐碎的循环大约是执行任务的“最佳方式”的两倍(并且更简洁)?-)我想速度和简洁性的优势必须使琐碎循环成为“最好的方法” “这样吧,对吧?-)

通过进一步牺牲紧凑性和可读性......:

$ python -mtimeit -s'import operator; L=range(12,52)' 'reduce(operator.mul, L, 1)'
100000 loops, best of 3: 10.7 usec per loop

...我们可以得到almost回到最简单、最明显、紧凑且可读的方法(简单、基本、琐碎的循环)轻松获得的性能。这指出了另一个问题lambda,其实:性能!对于足够简单的操作(例如乘法),与正在执行的实际操作相比,函数调用的开销相当大 -reduce (and map and filter)通常会迫使您在简单循环、列表推导式和生成器表达式中插入这样的函数调用,以实现内联操作的可读性、紧凑性和速度。

也许比上面斥责的“将 lambda 分配给名称”反惯用法更糟糕的是实际上以下反惯用法,例如按长度对字符串列表进行排序:

thelist.sort(key=lambda s: len(s))

而不是显而易见的、可读的、紧凑的、更快的

thelist.sort(key=len)

在这里,使用lambda除了插入一定程度的间接性之外什么也没做——没有任何好的效果,而且还有很多不好的效果。

使用动机lambda通常是允许使用map and filter而不是更可取的循环或列表理解,可以让您在线进行简单、正常的计算;当然,您仍然需要支付“间接级别”的费用。必须想知道“我应该在这里使用列表计算还是地图”并不是Pythonic:只要总是使用列表计算,当两者都适用并且您不知道选择哪一个时,基于“应该有一个,并且最好只有一种、明显的方式来做某事”。您经常会编写无法明智地转换为映射的列表计算(嵌套循环,if条款等),而没有调用map不能明智地将其重写为 listcomp。

Python 中完美的函数式方法通常包括列表推导式、生成器表达式、itertools、高阶函数、各种形式的一阶函数、闭包、生成器(有时还有其他类型的迭代器)。

itertools正如评论者指出的那样,确实包括imap and ifilter:区别在于,像所有 itertools 一样,它们是基于流的(例如map and filterPython 3 中的内置函数,但与 Python 2 中的内置函数不同)。itertools提供了一组可以很好地组合在一起的构建块以及出色的性能:特别是如果您发现自己可能正在处理很长(甚至无限!-)的序列,那么您应该熟悉 itertools - 它们的整体chapter http://docs.python.org/library/itertools.html文档中的内容有助于良好的阅读,并且recipes http://docs.python.org/library/itertools.html?highlight=itertools#recipes特别是很有启发性。

编写自己的高阶函数通常很有用,特别是当它们适合用作装饰者 http://docs.python.org/reference/compound_stmts.html#function(函数装饰器,如文档该部分中所解释的,以及类装饰器,在 Python 2.6 中引入)。一定要记得使用functools.wraps http://docs.python.org/library/functools.html?highlight=decorators#functools.wraps在你的函数装饰器上(以保持函数的元数据被包装)!

所以,总结一下……:任何你可以用来编码的东西lambda, map, and filter,您可以使用以下代码(通常是有利的)def(命名函数)和列表计算——通常会上升一级到生成器、生成器表达式或itertools,甚至更好。reduce符合“有吸引力的滋扰”的法律定义......:它是几乎没有适合这项工作的工具(这就是为什么它终于不再是 Python 3 中的内置工具了!-)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么要使用 Python 进行函数式编程? 的相关文章

随机推荐

  • 客户端断开连接后 Solr 查询继续吗?

    我对 Solr 长期运行查询遇到的问题有一个理论 但我不知道它是否正确 也不知道如何测试它 我正在使用 cURL 从应用程序查询 Solr cURL 的配置方式是 如果 Solr 在 3 秒内未发送响应 它将放弃并断开连接 从而允许托管 c
  • 在 Haskell 中阅读 GraphML

    我正在尝试将包含单个有向图的 GraphML 文件读入 HaskellData Graph http hackage haskell org package containers 0 2 0 1 docs Data Graph html为了
  • Pyramid 中基于动态用户的授权

    我正在跟进Pyramid 文档中的安全指南 http docs pylonsproject org projects pyramid 1 1 narr security html以及 wiki 教程添加授权 http docs pylons
  • jQuery AJAX JSONP 错误“意外的令牌”

    我正在尝试跨域JSONP在 Chrome 中打电话 但我总是回复 未捕获的语法错误 意外的标记 我尝试过 更改响应内容类型 设置 xhr 标头 JSON stringify 几乎是此处提供的大多数解决方案 但到目前为止没有任何效果 ajax
  • 如何在Python中打印3x3数组?

    我需要为名为 TicTackToe py 的游戏打印一个 3 x 3 数组 我知道我们可以使用以下方法以水平或垂直方式打印列表中的内容 listA a b c d e f g h i j VERTICAL PRINTING for item
  • 我们可以将 Identity Server 4 与客户端托管在同一应用程序中吗?

    我有两个关于 Identity Server 4 的直接问题 请帮助我更好地理解它们 他们是 1 为什么我们需要单独托管Identity Server 4 2 我们可以将 Identity Server 4 与客户端托管在同一应用程序中吗
  • Play服务粒度依赖错误

    我尝试对 Google Play Service 6 5 使用新的粒度依赖关系 在我的 gradle 中我设置 dependencies compile com android support appcompat v7 21 0 2 com
  • Android 计时器/计时器任务导致我的应用程序崩溃?

    只是在我的 mainActivity 的 onCreate 中测试一个简单的代码块 Timer timer2 new Timer TimerTask testing new TimerTask public void run Toast m
  • 如何将脚本的依赖项添加到 CMake 中的目标?

    链接我的程序后 我需要对其执行一些后处理 我添加了一个add custom command TARGET 效果很好 但是 这个额外的自定义命令运行一个脚本 未生成 它已签入代码库 并且我希望如果该脚本发生更改 目标将被视为过时 以便正确重建
  • 如何以“less”显示行号(GNU)

    执行的命令是什么less https linux die net man 1 less在左栏中显示行号 来自manual http unixhelp ed ac uk CGI man cgi less N 或 行号 导致在每个行的开头显示行
  • Xcode 9,我的 NSLog() 去哪里了?未显示在 Xcode 控制台或 Console.app 中

    我正在尝试在开发应用程序时进行一些基本的日志记录 我扔了一些NSLog s 到我的代码中 但没有任何内容打印到下面的 Xcode 控制台 从字面上看什么都没有 甚至没有应用程序启动时的一些启动信息等 我已将 Xcode 控制台设置为显示Al
  • 解析输入无效的 uiautomator 层次结构文件时出现意外错误

    我正在尝试使用跟踪视图检查应用程序性能的工具 但面临一些问题并且无法弄清楚 最初我使用这个命令来打开traceview E sdk android sdk tools gt monitor E calccalc 是我的traceview 日
  • Interface Builder 中的多个视图状态

    我正在处理一个有 3 种状态的屏幕 证实 Loading Error 前两个非常简单 因为只更改了标签文本 第三个比较棘手 因为我需要显示一条错误消息并在其上有一个重试按钮 另外 我希望将所有这些都放在一个控制器下 我想这是最简单的部分 问
  • 元素“sonar:sonar”的前缀“sonar”未绑定

    我有一个 build xml 文件 看起来像这样
  • JS中如何使用数组过滤对象数组? [复制]

    这个问题在这里已经有答案了 我希望你今天过得愉快 这非常简单 我有一个对象数组 我想在另一个数组的帮助下过滤掉它 场景如下图所示 var ob array a 1 col 2 abc a 2 col 2 xyz a 3 col 2 jkl
  • fullcalendar 选择回调未在移动设备中触发

    我在用全日历 https fullcalendar io 版本 2 9 1 我将日历渲染为议程周 当我从桌面上单击特定的时间段时 它会触发选择回调 但当我单击移动设备时却不会 问题是什么 selectable true select fun
  • 如何查找冻结模型的输入和输出节点

    我想使用张量流optimize for inference py来自模型动物园的冷冻模型的脚本 ssd mobilenet v1 coco 如何查找 确定模型的输入名称和输出名称 雇用张量板生成的图的版本 https i stack img
  • 三次贝塞尔曲线逆 GetPoint 方程:float for Vector <=> Vector for float

    给定结果值和四个点是否可以取回 float t 如果是这样 怎么办 public static Vector3 GetPoint Vector3 p0 Vector3 p1 Vector3 p2 Vector3 p3 float t t M
  • 如何在代码中访问 DataGridCell 的数据对象?

    基本上 我已经绑定了数据网格 使其类似于科目时间表 每行代表一个学期的科目 该学期内的每个单元格代表一个科目 我现在尝试添加拖放功能 以便您可以将其他主题拖到网格上 这将更新底层数据结构 我可以使用一些可视化树方法来查找用户将新主题拖动到的
  • 为什么要使用 Python 进行函数式编程?

    在工作中 我们过去常常以非常标准的面向对象方式来编写 Python 程序 最近 有几个人加入了功能性潮流 他们的代码现在包含更多的 lambda map 和reduce 我知道函数式语言有利于并发性 但是函数式 Python 编程真的有助于