Nic*_*ner 183 python functional-programming partial-application
部分应用很酷.什么功能functools.partial
提供你无法通过lambdas?
>>> sum = lambda x, y : x + y
>>> sum(1, 2)
3
>>> incr = lambda y : sum(1, y)
>>> incr(2)
3
>>> def sum2(x, y):
return x + y
>>> incr2 = functools.partial(sum2, 1)
>>> incr2(4)
5
Run Code Online (Sandbox Code Playgroud)
在functools
某种程度上更有效,或可读?
Ale*_*lli 247
functools.partial提供的功能是什么,你无法通过lambdas?
在额外功能方面并不多(但是,请参阅后面的内容) - 而且,可读性在旁观者眼中.
大多数熟悉函数式编程语言的人(特别是Lisp/Scheme系列中的人)似乎都很喜欢lambda
- 我说"最",绝对不是全部,因为Guido和我肯定是那些"熟悉"的人(但是lambda
在Python中
却被认为是眼中的异常... 他曾悔改过将其接受到Python中,并计划将其从Python 3中删除,作为"Python的故障"之一.
我完全支持他.(我喜欢lambda
Scheme ...虽然它在Python中的局限性,以及它的奇怪方式' 用其他语言,让我的皮肤爬行).
事实并非如此,但是,成群的lambda
爱好者-谁上演最亲密的事情见过Python的历史叛乱之一,直到圭多回溯和决定离开lambda
,在
几个可能的补充functools
(使函数返回的常量,身份,没有发生(为了避免明确地复制更多lambda
的功能),虽然partial
当然仍然存在(它不是完全重复,也不是一个眼睛).
请记住,lambda
身体仅限于表达,因此它有局限性.例如...:
>>> import functools
>>> f = functools.partial(int, base=2)
>>> f.args
()
>>> f.func
<type 'int'>
>>> f.keywords
{'base': 2}
>>>
Run Code Online (Sandbox Code Playgroud)
functools.partial
返回的函数装饰有对内省有用的属性 - 它包装的函数,以及它在其中修复的位置和命名参数.此外,可以在右后方覆盖命名参数(在某种意义上,"修复"是默认设置):
>>> f('23', base=10)
23
Run Code Online (Sandbox Code Playgroud)
所以,如你所见,它的定义并不像lambda s: int(s, base=2)
! - )
是的,你可以扭曲你的lambda给你一些 - 例如,关键字覆盖,
>>> f = lambda s, **k: int(s, **dict({'base': 2}, **k))
Run Code Online (Sandbox Code Playgroud)
但是我非常希望即使是最热情的lambda
人也不会认为这种恐怖比partial
电话更具可读性! - )."属性设置"部分更难,因为Python的"body是单一表达式"限制lambda
(加上赋值永远不能成为Python表达式的一部分)...最终"假装在表达式中赋值"通过扩展列表理解远远超出其设计限制......:
>>> f = [f for f in (lambda f: int(s, base=2),)
if setattr(f, 'keywords', {'base': 2}) is None][0]
Run Code Online (Sandbox Code Playgroud)
现在结合命名参数覆盖性,再加上三个属性的设置,到一个单一的表达,并告诉我是多么可读那将是... - !)
ars*_*ars 75
嗯,这是一个显示差异的例子:
In [132]: sum = lambda x, y: x + y
In [133]: n = 5
In [134]: incr = lambda y: sum(n, y)
In [135]: incr2 = partial(sum, n)
In [136]: print incr(3), incr2(3)
8 8
In [137]: n = 9
In [138]: print incr(3), incr2(3)
12 8
Run Code Online (Sandbox Code Playgroud)
Ivan Moore的这些帖子扩展了"lambda的限制"和python中的闭包:
Fre*_*Foo 26
在最新版本的Python(> = 2.7)中,您可以pickle
使用partial
,但不能lambda
:
>>> pickle.dumps(partial(int))
'cfunctools\npartial\np0\n(c__builtin__\nint\np1\ntp2\nRp3\n(g1\n(tNNtp4\nb.'
>>> pickle.dumps(lambda x: int(x))
Traceback (most recent call last):
File "<ipython-input-11-e32d5a050739>", line 1, in <module>
pickle.dumps(lambda x: int(x))
File "/usr/lib/python2.7/pickle.py", line 1374, in dumps
Pickler(file, protocol).dump(obj)
File "/usr/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/usr/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.7/pickle.py", line 748, in save_global
(obj, module, name))
PicklingError: Can't pickle <function <lambda> at 0x1729aa0>: it's not found as __main__.<lambda>
Run Code Online (Sandbox Code Playgroud)
Tri*_*ion 21
functools以某种方式更高效..?
作为部分答案,我决定测试性能.这是我的例子:
from functools import partial
import time, math
def make_lambda():
x = 1.3
return lambda: math.sin(x)
def make_partial():
x = 1.3
return partial(math.sin, x)
Iter = 10**7
start = time.clock()
for i in range(0, Iter):
l = make_lambda()
stop = time.clock()
print('lambda creation time {}'.format(stop - start))
start = time.clock()
for i in range(0, Iter):
l()
stop = time.clock()
print('lambda execution time {}'.format(stop - start))
start = time.clock()
for i in range(0, Iter):
p = make_partial()
stop = time.clock()
print('partial creation time {}'.format(stop - start))
start = time.clock()
for i in range(0, Iter):
p()
stop = time.clock()
print('partial execution time {}'.format(stop - start))
Run Code Online (Sandbox Code Playgroud)
在Python 3.3上它给出:
lambda creation time 3.1743163756961392
lambda execution time 3.040552701787919
partial creation time 3.514482823352731
partial execution time 1.7113973411608114
Run Code Online (Sandbox Code Playgroud)
这意味着部分需要更多的时间来创建,但执行的时间要少得多.这很可能是早期和晚期结合的影响,这在ars的答案中讨论过.
Leo*_*o.Z 11
除了Alex提到的额外功能外,functools.partial的另一个优点是速度.使用partial,您可以避免构造(和破坏)另一个堆栈帧.
部分生成的函数从原始函数继承docstring,而lambdas默认没有docstrings(尽管你可以通过设置任何对象的doc字符串__doc__
)
您可以在此博客中找到更多详细信息:Python中的部分功能应用程序
我在第三个例子中最快理解了意图。
当我解析 lambda 时,我期望比标准库直接提供的更复杂/奇怪。
另外,您会注意到第三个示例是唯一一个不依赖于sum2
;的完整签名的示例。从而使其耦合更加松散。