PEP 8规定:

导入总是放在文件的顶部,就在任何模块注释和文档字符串之后,在模块全局变量和常量之前。

然而,如果我导入的类/方法/函数只在很少的情况下使用,那么在需要时进行导入肯定会更有效吗?

这不是:

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()

当前回答

为了完成老谋子的回答和最初的问题:

当我们不得不处理循环依赖关系时,我们可以做一些“技巧”。假设我们正在处理模块a.py和b.py,它们分别包含x()和b.y()。然后:

我们可以移动模块底部的from导入之一。 我们可以将其中一个from导入移动到实际需要导入的函数或方法中(这并不总是可行的,因为您可能从多个地方使用它)。 我们可以把其中一个import改成import,就像import a

总结一下。如果您没有处理循环依赖关系,也没有使用某种技巧来避免它们,那么最好将所有导入放在顶部,因为原因已经在这个问题的其他答案中解释过了。请在做这些“技巧”时附上评论,这总是受欢迎的!:)

其他回答

可读性

除了启动性能外,本地化import语句还需要考虑可读性。例如,在我目前的第一个python项目中使用python行号1283到1296:

listdata.append(['tk font version', font_version])
listdata.append(['Gtk version', str(Gtk.get_major_version())+"."+
                 str(Gtk.get_minor_version())+"."+
                 str(Gtk.get_micro_version())])

import xml.etree.ElementTree as ET

xmltree = ET.parse('/usr/share/gnome/gnome-version.xml')
xmlroot = xmltree.getroot()
result = []
for child in xmlroot:
    result.append(child.text)
listdata.append(['Gnome version', result[0]+"."+result[1]+"."+
                 result[2]+" "+result[3]])

如果import语句在文件的顶部,我将不得不向上滚动很长一段距离,或按Home键,以找出ET是什么。然后我将不得不返回到第1283行继续阅读代码。

实际上,即使import语句像许多人那样位于函数(或类)的顶部,也需要向上和向下分页。

很少会显示Gnome版本号,因此在文件顶部导入会引入不必要的启动延迟。

I do not aspire to provide complete answer, because others have already done this very well. I just want to mention one use case when I find especially useful to import modules inside functions. My application uses python packages and modules stored in certain location as plugins. During application startup, the application walks through all the modules in the location and imports them, then it looks inside the modules and if it finds some mounting points for the plugins (in my case it is a subclass of a certain base class having a unique ID) it registers them. The number of plugins is large (now dozens, but maybe hundreds in the future) and each of them is used quite rarely. Having imports of third party libraries at the top of my plugin modules was a bit penalty during application startup. Especially some thirdparty libraries are heavy to import (e.g. import of plotly even tries to connect to internet and download something which was adding about one second to startup). By optimizing imports (calling them only in the functions where they are used) in the plugins I managed to shrink the startup from 10 seconds to some 2 seconds. That is a big difference for my users.

所以我的答案是否定的,不要总是把导入放在模块的顶部。

以下是对这个问题的最新答案总结 而且 相关的 的问题。

PEP 8 recommends putting imports at the top. It's often more convenient to get ImportErrors when you first run your program rather than when your program first calls your function. Putting imports in the function scope can help avoid issues with circular imports. Putting imports in the function scope helps keep maintain a clean module namespace, so that it does not appear among tab-completion suggestions. Start-up time: imports in a function won't run until (if) that function is called. Might get significant with heavy-weight libraries. Even though import statements are super fast on subsequent runs, they still incur a speed penalty which can be significant if the function is trivial but frequently in use. Imports under the __name__ == "__main__" guard seem very reasonable. Refactoring might be easier if the imports are located in the function where they're used (facilitates moving it to another module). It can also be argued that this is good for readability. However, most would argue the contrary, i.e. Imports at the top enhance readability, since you can see all your dependencies at a glance. It seems unclear if dynamic or conditional imports favour one style over another.

有趣的是,到目前为止,没有一个回答提到并行处理,当序列化的函数代码被推到其他核心时,可能需要将导入放在函数中,例如在ipyparallel的情况下。

我想提一下我的一个用例,与@John Millikin和@ v.k.提到的用例非常相似:

可选的进口

我使用Jupyter Notebook进行数据分析,我使用相同的IPython Notebook作为所有分析的模板。在某些情况下,我需要导入Tensorflow来做一些快速的模型运行,但有时我工作的地方,Tensorflow没有设置/导入很慢。在这些情况下,我将依赖于tensorflow的操作封装在一个helper函数中,在该函数中导入tensorflow,并将其绑定到一个按钮。

这样,我就可以“重新启动并运行全部”,而不必等待导入,也不必在导入失败时恢复其余的单元格。