在速度和内存效率方面,将Python模块和/或函数导入到函数内部的优缺点是什么?
每次运行函数时是否会重新导入,还是只会在开始导入一次,无论是否运行函数?
在速度和内存效率方面,将Python模块和/或函数导入到函数内部的优缺点是什么?
每次运行函数时是否会重新导入,还是只会在开始导入一次,无论是否运行函数?
每次运行函数时,它是否会重新导入?
不会;或者更确切地说,Python模块在每次导入时都会被缓存,因此第二次(或第三次、第四次……)导入实际上并不会强制其再次经历整个导入过程。1
关于好处:这取决于情况,我想。如果您只需要很少运行一个函数,并且不需要在其他任何地方导入该模块,则仅在该函数中导入它可能会有益。或者如果存在名称冲突或其他原因,您不希望该模块或该模块中的符号在所有地方都可用,则可能只想在特定函数中导入它。(当然,在这些情况下,总是可以使用它是否在开始时导入,无论函数是否运行?
from my_module import my_function as f
。)import plotly
放在调用它的函数内部,大大减少了我的 web2py 应用程序加载时间。 - laviexgoo
时,goo.py
(或其他可导入形式)将被加载,并将sys.modules['goo']
设置为所构建的模块对象。在程序运行的同一次中进行的任何未来导入(再次在函数内或外部),只需查找sys.modules['goo']
并将其绑定到适当作用域中的裸名goo
。字典查找和名称绑定都是非常快速的操作。
假设第一个import
在程序运行期间完全摊销,那么将“适当作用域”设置为模块级别意味着每个goo.this
、goo.that
等的使用都需要进行两次字典查找——一次是goo
的查找,一次是属性名称的查找。将其设置为“函数级别”每次运行函数时需要进行一个额外的局部变量设置(比字典查找部分更快!),但可以为每个goo.this
(等等)访问节省一个字典查找(用本地变量查找交换,非常快),从而基本上减少这些查找所需的时间。
我们谈论的是微秒级别的差异,因此这几乎不是一项值得优化的工作。将import
放在函数内的一个潜在的重大优点是,该函数在给定程序运行中可能根本不需要,例如,该函数处理错误、异常和一般稀有情况;如果是这种情况,则任何不需要该功能的运行都不会执行导入(这是微秒级别而不仅是纳秒级别的节省),只有需要该功能的运行才会支付(适度但可测量的)代价。
这仍然是一种只在极端情况下才值得的优化方法,在尝试挤出微秒级时间之前,还有许多其他方法可以考虑。
import string, itertools, fractions, heapq, re, array, bisect, collections, math, os
的脚本进行比较。前者平均需要 180 毫秒,而后者需要 230 毫秒。因此,这不是微秒级别的差别,而是数十毫秒(可能是磁盘访问发生的原因?)。对于多次运行的小型脚本(例如服务网络请求),这一点很重要。 - Evgeni Sergeev该函数执行第一次时只会导入一次。
优点:
缺点:
grep import /path/to/module
这样的命令,它将显示该模块导入的所有模块。 - user1465368我建议您不要问“X会提高我的性能吗?”这样的问题,而是使用性能分析工具确定程序花费时间的实际情况,并根据您可以获得最大收益的地方进行优化。
然后,您可以使用性能分析工具来确保您的优化确实带来了效益。
在函数内部导入模块将会在第一次运行该函数时有效地导入模块。
无论您是在顶部导入还是在函数运行时导入,它都应该同样快速地导入。这通常不是在def中导入的好理由。优点是什么?如果未调用该函数,则不会导入。如果您的模块只需要用户安装某个特定的模块来使用您的特定函数,那么这实际上是一个合理的原因...
如果这不是您这样做的原因,那几乎肯定是一个糟糕的想法。
当函数第一次被调用时,它会进行一次导入。
如果我有一个在导入模块中很少使用且是唯一需要导入的函数,我可以想象以这种方式执行。虽然看起来有些牵强...
import
模块,然后在函数内部将模块分配给本地变量。为了使分配有意义,在函数内部至少需要访问该模块 4 次-如果您使用的频率比这还要低,那么在全局级别进行直接的模块. 符号查找与本地赋值/查找相比不会更慢。 - Nick Bastin