在下面的代码示例中,我有两个更高级别的函数 factory1
和 factory2
,它们生成具有相同行为的函数。第一个工厂 factory1
通过让返回的函数根据工厂的 bool 值更改行为,避免显式定义两个不同的函数。在此示例中,此功能的用处并不那么明显,但如果要生成的函数更复杂,则显式写出该函数的两个几乎相同的副本(如 factory2
中所做的那样)将不利于可读性和可维护性.
但是,从计时结果可以看出,factory2
的实现速度更快。
有没有办法在不显式定义两个替代函数的情况下实现 factory2
的性能?
def factory1(condition):
def fn():
if condition:
return "foo"
else:
return "bar"
return fn
def factory2(condition):
def foo_fn():
return "foo"
def bar_fn():
return "bar"
if condition:
return foo_fn
else:
return bar_fn
def test1():
fn = factory1(True)
for _ in range(1000):
fn()
def test2():
fn = factory2(True)
for _ in range(1000):
fn()
if __name__ == '__main__':
import timeit
print(timeit.timeit("test1()", setup="from __main__ import test1"))
# >>> 62.458039999
print(timeit.timeit("test2()", setup="from __main__ import test2"))
# >>> 49.203676939
编辑:更多上下文
我问的原因是我正在尝试生成一个看起来像这样的函数:
def function(data):
data = some_transform(data)
if condition:
# condition should be considered invariant at time of definition
data = transform1(data)
else:
data = transform2(data)
data = yet_another_transform(data)
return data
最佳答案
根据“显式定义两个函数”的含义,请注意,在检查条件之前,您不必执行 def
语句:
def factory3(condition):
if condition:
def fn():
return "foo"
else:
def fn():
return "bar"
return fn
有人可能会反对,在确定运行时使用哪一个来定义函数之前,仍然必须编译两个代码对象。在这种情况下,您可能会在动态构造的字符串上使用 exec
。 注意 对于除了我将在此处展示的静态示例之外的任何内容,都需要仔细完成此操作。请参阅the old definition for namedtuple
一个很好的(?)例子。
def factory4(condition):
code = """def fn():\n return "{}"\n""".format("foo" if condition else "bar")
exec(code)
return fn
更安全的替代方案可能是使用闭包:
def factory5(condition):
def make_fun(val):
def _():
return val
return _
if condition:
return make_fun("foo")
else:
return make_fun("bar")
make_fun
也可以在 factory5
外部定义,因为它根本不依赖于condition
。
根据您的编辑,我认为您只是想实现依赖项注入(inject)。不要在函数中放置 if
语句;传递 transform1
或 transform2
作为参数:
def function(transform):
def _(data):
data = some_transform(data)
data = transform(data)
data = yet_another_transform(data)
return data
return _
if condition:
thing = function(transform1)
else:
thing = function(transform2)
关于python - python 闭包中的条件性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56582050/