我正在寻找一种在 python 中部分应用函数的方法,该方法易于理解、可读、可重用,并且尽可能减少编码人员出错的可能性。最重要的是,我希望样式尽可能高效——堆栈上的帧越少越好,部分应用函数的内存占用也越少也是可取的。我考虑了 4 种风格,并在下面写了例子:
import functools
def multiplier(m):
def inner(x):
return m * x
return inner
def divide(n,d):
return n/d
def divider(d):
return functools.partial(divide,d=d)
times2 = multiplier(2)
print(times2(3)) # 6
by2 = divider(2)
print(by2(6)) # 3.0
by3 = functools.partial(divide,d=3)
print(by3(9)) # 3.0
by4 = lambda n: divide(n,4)
print(by4(12)) # 3.0
我对它们的分析是:
times2
是一个嵌套的东西。我想 python 用 m
绑定(bind)关闭,一切都很好。代码可读(我认为)并且易于理解。没有外部库。这是我今天使用的样式。
by2
有一个明确命名的函数,这对用户来说很简单。它使用 functools,所以它给你额外的导入。我在某种程度上喜欢这种风格,因为它是透明的,如果我愿意,可以选择以其他方式使用divide
。将此与无法访问的 inner
进行对比。
by3
类似于 by2
,但是强制代码的读者适应 functools.partial
因为他们就在脸上。我不太喜欢的是 PyCharm 不能给我的工具提示告诉我 functools.partial
的参数应该是什么,因为它们实际上是 by3
的参数。每次定义一些新的部分应用程序时,我都必须自己知道 divide
的签名。
by4
易于输入,因为我可以获得自动完成功能。它不需要导入 functools
。我认为它看起来不是pythonic。此外,我总是对在 python 中使用 lambda 工作的变量/闭包的范围界定感到不舒服。永远不确定那是如何表现的....
样式之间的逻辑区别是什么?这对内存和 CPU 有何影响?
最佳答案
第一种方式似乎是最有效的。我调整了您的代码,以便所有 4 个函数计算完全相同的数学函数:
import functools,timeit
def multiplier(m):
def inner(x):
return m * x
return inner
def mult(x,m):
return m*x
def multer(m):
return functools.partial(mult,m=m)
f1 = multiplier(2)
f2 = multer(2)
f3 = functools.partial(mult,m=2)
f4 = lambda x: mult(x,2)
print(timeit.timeit('f1(10)',setup = 'from __main__ import f1'))
print(timeit.timeit('f2(10)',setup = 'from __main__ import f2'))
print(timeit.timeit('f3(10)',setup = 'from __main__ import f3'))
print(timeit.timeit('f4(10)',setup = 'from __main__ import f4'))
典型输出(在我的机器上):
0.08207898699999999
0.19439769299999998
0.20093803199999993
0.1442435820000001
这两种 functools.partial
方法是相同的(因为其中一个只是另一个的包装器),第一个快两倍,最后一个介于两者之间(但更接近首先)。在简单的闭包上使用 functools
有明显的开销。由于闭包方法可以说也更具可读性(并且比不能很好地扩展到更复杂函数的 lambda 更灵活),我会接受它。
关于python - 在 Python 中部分应用的高效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57822851/