导入语句是否应该始终位于模块的顶部?

PEP 08指出: 程序员

导入老是放在文件的顶部,紧随任何模块注释和文档字符串以后,以及模块全局变量和常量以前。 api

可是,若是仅在极少数状况下使用我要导入的类/方法/函数,那么在须要时进行导入确定会更有效吗? 模块化

这不是吗? 函数

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”模块,第一个将在加载时失败,而第二个在调用该方法以前不会失败。 spa

补充说明:在IronPython中,导入可能比CPython中昂贵得多,由于代码基本上是在导入时进行编译的。 调试


#2楼

我没必要担忧过多地预先加载模块的效率。 模块占用的内存不会很大(假设它足够模块化),启动成本能够忽略不计。 code

在大多数状况下,您但愿将模块加载到源文件的顶部。 对于阅读您的代码的人来讲,分辨哪一个函数或对象来自哪一个模块变得容易得多。 对象

将模块导入代码中其余地方的一个很好的理由是,若是该模块用于调试语句中。

例如:

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异常并以合理的方式对其进行处理。

相关文章
相关标签/搜索