PEP 08指出:
导入总是放在文件的顶部,紧随任何模块注释和文档字符串之后,以及模块全局变量和常量之前。
但是,如果仅在极少数情况下使用我要导入的类/方法/函数,那么在需要时进行导入肯定会更有效吗?
这不是吗?
class SomeClass(object):
def not_often_called(self)
from datetime import datetime
self.datetime = datetime.now()
比这更有效?
from datetime import datetime
class SomeClass(object):
def not_often_called(self)
self.datetime = datetime.now()
#1楼
当函数被调用零次或一次时,第一种变体的确比第二种变体更有效。 但是,在第二次及其后的调用中,“导入每个调用”方法实际上效率较低。 请参阅此链接以获取延迟加载技术,该技术通过执行“延迟导入”结合了两种方法的优点。
但是,除了效率之外,还有其他原因导致您可能会偏爱一个。 一种方法是使阅读该模块相关代码的人更加清楚。 它们还具有非常不同的故障特征-如果没有“ datetime”模块,第一个将在加载时失败,而第二个在调用该方法之前不会失败。
补充说明:在IronPython中,导入可能比CPython中昂贵得多,因为代码基本上是在导入时进行编译的。
#2楼
我不必担心过多地预先加载模块的效率。 模块占用的内存不会很大(假设它足够模块化),启动成本可以忽略不计。
在大多数情况下,您希望将模块加载到源文件的顶部。 对于阅读您的代码的人来说,分辨哪个函数或对象来自哪个模块变得容易得多。
将模块导入代码中其他地方的一个很好的理由是,如果该模块用于调试语句中。
例如:
do_something_with_x(x)
我可以使用以下命令调试它:
from pprint import pprint
pprint(x)
do_something_with_x(x)
当然,将模块导入代码中其他位置的另一个原因是是否需要动态导入它们。 这是因为您几乎别无选择。
我不必担心过多地预先加载模块的效率。 模块占用的内存不会很大(假设它足够模块化),启动成本可以忽略不计。
#3楼
在大多数情况下,这样做对于保持清晰性和明智性很有用,但并非总是如此。 以下是几个可能会在其他地方导入模块的情况的示例。
首先,您可以拥有一个带有以下形式的单元测试的模块:
if __name__ == '__main__':
import foo
aa = foo.xyz() # initiate something for the test
其次,您可能需要在运行时有条件地导入一些不同的模块。
if [condition]:
import foo as plugin_api
else:
import bar as plugin_api
xx = plugin_api.Plugin()
[...]
在其他情况下,您可能会将导入放置在代码的其他部分中。
#4楼
这是一个折衷,只有程序员才能决定进行。
情况1通过在需要之前不导入datetime模块(并进行可能需要的任何初始化)来节省一些内存和启动时间。 请注意,“仅在调用时”执行导入也意味着“在调用时每次”执行导入操作,因此,第一个调用之后的每个调用仍会产生执行导入的额外开销。
情况2通过预先导入datetime来节省一些执行时间和延迟,这样not_often_drawn()在被调用时将更快地返回,并且也不会在每次调用时都导致导入开销。
除了效率外,如果import语句在...前面,则更容易在前面看到模块依赖性。 将它们隐藏在代码中会使您更难于找到所需的模块。
就个人而言,除了单元测试之类的东西外,我通常都遵循PEP,因此我不希望总是加载它,因为我知道除了测试代码之外不会使用它们。
#5楼
Curt提出了一个很好的观点:第二个版本更清晰,它将在加载时而不是以后失败,并且出乎意料地失败。
通常,我不必担心模块的加载效率,因为它的速度(a)非常快,而(b)大多仅在启动时发生。
如果必须在意外的时刻加载重量级模块,则使用__import__
函数动态加载它们可能更有意义,并确保捕获ImportError
异常并以合理的方式对其进行处理。
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3167338