将python导入放在函数中是否存在性能成本?

Pau*_*ipp 16 python

我经常使用Django构建相当复杂的python应用程序.为了简化应用程序间接口,我有时会使用从模型中抽象出来的service.py模块.

作为这些"聚合功能",它们经常以循环导入结束,通过将import语句放在服务函数中可以轻松消除这些导入.

是否存在与通常移动进口尽可能接近其使用点相关的显着性能或内存成本?例如,如果我只在文件的一个函数中使用特定的导入名称,那么将导入放在该特定函数中而不是在传统位置的文件顶部似乎很自然.

此问题与此问题略有不同,因为每个导入都在函数名称空间中.

cod*_*edd 15

如果您担心的话,导入模块的点不会导致性能下降.模块是单例,import每次import遇到语句时都不会编辑.但是,如何进行导入以及后续属性查找确实会产生影响.

例如,如果您import math和每次需要使用sin(...)您必须执行的功能时math.sin(...),这通常会比直接执行from math import sin和使用更慢,sin(...)因为系统不必继续查找模块中的函数名称.

此查找惩罚适用于使用点访问的任何内容,.并且在循环中尤其明显.因此,建议在性能关键循环/部分中获取可能需要经常使用/调用的内容的本地引用.

例如,使用原始import math示例,在关键循环之前,您可以执行以下操作:

# ... within some function
sin = math.sin
for i in range(0, REALLY_BIG_NUMBER):
    x = sin(i)   # faster than:  x = math.sin(x)
    # ...
Run Code Online (Sandbox Code Playgroud)

这是一个简单的例子,但请注意,您可以使用其他对象(例如列表,词典等)上的方法执行类似操作.

我可能会更关注你提到的循环进口.如果您的目的是通过将import语句移动到更多"本地"位置(例如在特定函数或代码块中等)来"修复"循环导入,那么您可能需要解决更深层次的问题.

就个人而言,我通常会将导入保留在模块的顶部.由于没有充分理由而偏离该模式可能会使您的代码更难以通过,因为模块的依赖性不会立即显现(即,import语句分散在整个代码中而不是单个位置).

它也可能使循环依赖问题看起来更难调试,更容易陷入困境.毕竟,如果上面没有列出模块,有人可能会高兴地认为你的模块A不依赖于模块B,然后import A在已经隐藏在某个深黑暗角落B时添加一个输入.Aimport B


基准样本

这是使用查找符号的基准:

>>> timeit('for i in range(0, 10000): x = math.sin(i)', setup='import math', number=50000)
89.7203312900001
Run Code Online (Sandbox Code Playgroud)

另一个使用查找表示法的基准测试:

>>> timeit('for i in range(0, 10000): x = sin(i)', setup='from math import sin', number=50000)
78.27029322999988
Run Code Online (Sandbox Code Playgroud)

这里有10+的差异.

请注意,您的增益取决于程序运行此代码所花费的时间 - 这是一个性能关键部分而不是偶发函数调用.


Pau*_*son 8

看到这个问题。

基本上每当你导入一个模块时,如果它在它之前被导入,它将使用缓存值。

这意味着性能将在第一次加载模块时受到影响,但是一旦加载,它将缓存值以供将来调用它。