是否有内置的" apply"函数(像" lambda f:f()")就像以前在Python 2中一样?

时间:2018-03-29 15:29:57

标签: python python-3.x apply higher-order-functions built-in

关注this question,我意识到如果你想要并行运行一系列函数,使用multiprocessing Pool.map会有点尴尬:< / p>

from multiprocessing import Pool

def my_fun1(): return 1
def my_fun2(): return 2
def my_fun3(): return 3

with Pool(3) as p:
   one, two, three = p.map(lambda f: f(), [my_fun1, my_fun2, my_fun3])

我并不是说它完全是神秘的,但我认为我预计会有一些传统名称,即使只是在functools之内,与apply / {{3}类似在JavaScript中(是的,我知道JavaScript在定义这些函数的时候没有lambdas,不,我不是说JavaScript是一种示例性的编程语言,只是一个例子)。事实上,我绝对认为这样的事情应该出现在call中,但是(除非我的眼睛欺骗了我)似乎缺席了。我读到operator分辨率是为了让人们定义自己的琐碎功能,在这种情况下我理解得更好,因为你可能会想要几种不同的变化,但这对我来说感觉有些缺失

编辑:正如评论中所指出的,Python 2曾经为此目的使用in the case of the identity function函数。

2 个答案:

答案 0 :(得分:5)

首先,让我们看看实际问题。

对于2.3以上的任何Python,你不仅可以简单地写出你的无论证apply,还可以写一个完美转发apply,作为一个单行,如{{3}中所述}:

  

使用apply()相当于function(*args, **keywords)

换句话说:

def apply(function, *args, **keywords):
    return function(*args, **keywords)

...或者,作为内联lambda:

lambda f, *a, **k: f(*a, **kw)

当然,C实现速度要快一些,但这几乎不相关。 1

如果您不止一次使用此功能,我认为将该功能定义为脱机并按名称重复使用它可能更清晰,但lamdba版本简单明了(对您而言更是如此) no-args用例)我无法想象有人抱怨它。

另外,请注意,如果您了解自己在做什么,而不是更少,这实际上比identity更为微不足道。对于identity,使用多个参数(或关键字参数)返回的内容是不明确的,因此您必须决定所需的行为;使用apple,只有一个明显的答案,而且几乎不可能出错。

至于历史:

Python与JavaScript一样,最初没有lambda。很难为2.6之前的版本挖掘可链接的文档,并且很难在2.3之前找到它们,但我认为lambda在1.5中被添加,并最终达到可以用于2.2左右的完美转发的程度。在此之前,文档建议使用apply进行转发,但之后,文档建议使用lambda代替apply。事实上,不再推荐使用apply

所以在2.3中,该函数已被弃用。 2

在导致3.0的Python-3000讨论期间,Guido建议除了可能 mapfilter之外的所有“函数式编程”函数都是不必要的。 3 其他人为reducepartial提供了良好的案例。 4 但案件的很大一部分原因是它们实际上并不容易写(完全一般的形式),容易出错。 apply不是这样。此外,人们能够在现实世界的代码库中找到reducepartial的相关用途,但任何人都可以找到的apply的唯一用途是旧的2.3之前的代码。实际上,它甚至不值得将2to3工具转换为apply调用。

the 2.x docs for apply总结了删除它的最终理由:

  

apply():使用f(*args, **kw)代替[2]

该脚注链接到Guido的一篇名为“Python Regrets”的文章,该文章现在是404链接。随附的PowerPoint演示文稿是PEP 3100,或者您可以查看他为其编写的演示文稿的still available。但它真正说的是同一个单行,而IIRC,唯一进一步的讨论是“我们已经在2.3中有效地摆脱了它。”

<子> 1。在大多数必须应用函数的惯用Python代码中,该函数内部的工作非常繁重。当然,在你的情况下,调用函数(pickling参数并将它们传递给管道)的开销更大。重要的一个例子是当你正在进行“Haskell风格的函数式编程”而不是“Lisp风格”时 - 即很少有函数定义,以及通过转换函数和组合结果而产生的大量函数。但是在Python中已经非常缓慢(并且堆栈繁重),这不是一件合理的事情。 (平面使用装饰器来应用包装或三个工作很好,但是一个潜在的无限包装链会破坏你的性能。)

<子> 2。正式的弃用机制尚不存在,因此它只是转移到文档中的“非必要的内置函数”部分。但是,从2.3文档中可以看出它被追溯被认为是弃用的。

<子> 3。 Guido最初想要摆脱它们;正如你在“遗憾”翻书中看到的那样,列表理解可以更好地完成同样的工作。但是,提升itertools.imap代替map意味着它可能会变得懒惰,就像新的zip一样,因此比理解更好。我不确定为什么Guido不只是用生成器表达式做出相同的参数。

<子> 4。我不确定Guido本人是否曾相信reduce,但整个核心开发者都是。

答案 1 :(得分:1)

如果你做了一行额外的工作,它就在operator中:

>>> def foo():
...     print 'hi'
... 
>>> from operator import methodcaller
>>> call = methodcaller('__call__')
>>> call(foo)
hi

当然,call = lambda f: f()也只有一行......