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

喜夏-厌秋 提交于 2020-02-26 16:35:34

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!