您可以使用闭包优化函数中的导入吗?

Can you optimize imports in functions using closures?

These two 问题涉及在函数内部使用 import 与在模块顶部使用 import。我不需要被说服将我的进口商品放在首位,这样做是有充分理由的。但是,为了更好地理解技术问题,我想提出后续问题。

您能否通过使用闭包并仅在函数的第一个 运行 上导入来获得两全其美的性能?


具体来说,假设您有如下代码:

import sys
def get_version():
    return sys.version

您希望导入仅在函数被调用时发生,因此将其移入:

def get_version():
    import sys
    return sys.version

但是现在如果 被调用很多,它会很慢,所以你尝试更复杂的东西:

def _get_version():
    import sys

    def nested():
        return sys.version

    global get_version
    get_version = nested
    return nested()
get_version = _get_version

现在至少一个基本的性能测试表明最后一个选项比第一个稍微慢一点(大约 110% 的时间),但比第二个快得多(大约 20% 的时间)。


首先,这真的有效吗?我的测量值是否准确地描述了第二个示例做的更多,或者它是我测量事物的方式的产物。

其次,闭包是否会导致速度减慢 - 除了函数第一次 运行?

闭包取消引用并不比全局查找快:

>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)
>>> from timeit import timeit
>>> glob = 'foo'
>>> def f1(): return glob
...
>>> def closure():
...     closed_over = 'bar'
...     def f2():
...         return closed_over
...     return f2
...
>>> f2 = closure()
>>> timeit(f1, number=10**7)
0.8623221110319719
>>> timeit(f2, number=10**7)
0.872071701916866

此外,即使它 更快,但以可读性为代价是不值得的,当您真正需要优化代码时有更快的选项可用时,当然不值得。

本地变量总是最快的选择,如果您真的需要优化从紧密循环调用的代码,正确的混合方法是使用函数参数默认值:

import sys.version

def get_version(_sys_version=sys.version):
    return _sys_version

如果您担心启动时导入的初始文件加载的影响,也许您应该查看 py-demandimport project,它将加载模块推迟到第一次使用它们时。