在速度和内存效率方面,在函数内导入Python模块和/或函数的优缺点是什么?
每次运行函数时是重新导入,还是在开头只运行一次,无论函数是否运行?
答案 0 :(得分:114)
每次运行该函数时都会重新导入吗?
没有;或者更确切地说,Python模块在每次导入时基本上都被缓存,因此导入第二个(或第三个或第四个......)时间实际上并不会强制它们再次完成整个导入过程。 1
无论函数是否运行,它都会在开头导入一次吗?
至于好处:这取决于我猜。如果您可能很少运行某个函数而且不需要在其他任何地方导入模块,那么可能只能在该函数中导入它。或者如果存在名称冲突或其他原因,您不希望模块中的模块或符号可用无处不在,您可能只想在特定功能中导入它。 (当然,这些情况总是from my_module import my_function as f
。)
在一般实践中,它可能没那么有益。事实上,大多数Python风格指南都鼓励程序员将所有导入放在模块文件的开头。
答案 1 :(得分:36)
第一次import goo
来自任何地方(函数内部或外部),goo.py
(或其他可导入的形式)被加载,sys.modules['goo']
被设置为由此构建的模块对象。在程序的同一次运行中的任何未来导入(同样,无论是在函数内部还是外部)只需查找sys.modules['goo']
并将其绑定到适当范围内的裸名goo
。 dict查找和名称绑定是非常快速的操作。
假设第一个import
完全按照程序的运行进行摊销,将“适当范围”设置为模块级意味着每次使用goo.this
,goo.that
等都是两个dict查找 - 一个用于goo
,另一个用于属性名称。拥有它是“功能级别”每次运行函数需要一个额外的局部变量设置(甚至比字典查找部分更快!)但是为每个{保存一个dict查找(将其交换为局部变量查找,非常快) {1}}(等)访问,基本上将这种查找时间减半。
我们谈论的是几纳秒这样或那样,所以这几乎不值得进行优化。在函数中具有goo.this
的一个潜在的实质性优点是在程序的给定运行中根本不需要该函数,例如,该函数一般处理错误,异常和罕见情况。 ;如果是这种情况,任何不需要该功能的运行都不会执行导入(这是一个微秒的节省,而不仅仅是纳秒),只有需要该功能的运行才会支付(适度但可衡量的)价格。 / p>
这仍然是一种在非常极端情况下值得的优化,在尝试以这种方式挤出微秒之前,我会考虑很多其他的。
答案 2 :(得分:9)
当函数第一次执行时,它会导入一次。
优点:
缺点:
答案 3 :(得分:5)
在函数内部导入将有效地导入模块一次..第一次运行该函数。
无论是在顶部导入还是在运行函数时,它都应该以同样快的速度导入。这通常不是导入def的好理由。优点?如果没有调用该函数,它将不会被导入..如果你的模块只需要用户安装某个模块,如果他们使用你的特定功能,这实际上是一个合理的原因......
如果他不是因为你这样做,那几乎肯定是一个令人讨厌的想法。
答案 4 :(得分:3)
我可能会建议一般不要问“X会改善我的表现吗?”您使用性能分析来确定您的计划实际花费时间的位置,然后根据您将获得最大收益的位置应用优化?
然后您可以使用分析来确保您的优化实际上也使您受益。
答案 5 :(得分:2)
第一次调用函数时导入一次。
如果我在导入的模块中有一个很少使用的函数并且是唯一需要导入的函数,我可以想象这样做。看起来相当牵强,但是......