在函数内导入是 Pythonic 吗?
PEP 8 说:
- 导入的内容总是放在文件的最上面,紧接着模块的注释和文档字符串之后,然后是模块的全局变量和常量。
有时候,我会违反 PEP 8 的规定。有时我会在函数内部导入东西。一般来说,如果某个导入只在一个函数内使用,我就会这样做。
大家有什么看法吗?
编辑(我觉得在函数中导入可能是个好主意的原因):
主要原因:这可以让代码更清晰。
- 当我查看一个函数的代码时,可能会问自己:“函数/类 xxx 是什么?”(xxx 是在函数内部使用的)。如果我把所有的导入都放在模块的顶部,我就得去那里查找 xxx 是什么。这在使用
from m import xxx
时尤其麻烦。看到函数中的m.xxx
可能会告诉我更多信息。具体来说,m
是什么?是一个知名的顶级模块/包(import m
)吗?还是一个子模块/包(from a.b.c import m
)? - 在某些情况下,把额外的信息(“xxx 是什么?”)放在 xxx 使用的地方附近,可以让这个函数更容易理解。
10 个回答
24
这里有四种我们使用的导入方式
import
(还有from x import y
和import x as y
)通常放在文件的最上面导入的选择。也放在最上面。
import settings if setting.something: import this as foo else: import that as foo
条件导入。通常用于处理 JSON、XML 等库。也放在最上面。
try: import this as foo except ImportError: import that as foo
动态导入。目前我们只有一个例子。
import settings module_stuff = {} module= __import__( settings.some_module, module_stuff ) x = module_stuff['x']
需要注意的是,这种动态导入不是引入代码,而是引入用 Python 写的复杂数据结构。这有点像我们手动制作的腌制数据。
这种方式通常也放在模块的最上面。
为了让代码更清晰,我们会这样做:
保持模块简短。
如果我把所有的导入都放在模块的最上面,我就可以去那里查看某个名称的定义。如果模块很短,这样做很简单。
在某些情况下,把额外的信息放在名称使用的地方,可以让函数更容易理解。如果模块很短,这样做也很简单。
58
在这方面,我有两个地方会违反PEP 8的规范:
- 循环导入:模块A导入了模块B,但模块B里又需要模块A(这通常说明我需要重新整理这些模块,以消除这种循环依赖)。
- 插入pdb断点:
import pdb; pdb.set_trace()
这样做很方便,因为我不想在每个可能需要调试的模块顶部都写import pdb
,而且在我移除断点时,记得去掉这个导入也很简单。
除了这两种情况,最好把所有的导入放在文件的顶部。这样可以让依赖关系更加清晰。
116
从长远来看,我觉得把大部分的导入放在文件的顶部会更好,这样你一眼就能看出这个模块有多复杂,因为你可以看到它需要导入哪些东西。
如果我在一个已有的文件里添加新代码,我通常会在需要的地方先导入,然后如果这段代码留在那儿,我就会把导入的那一行移动到文件的顶部,让它变得更正式。
还有一点,我喜欢在任何代码运行之前就遇到一个ImportError
错误——这算是一种 sanity check(理智检查),所以这也是把导入放在顶部的另一个原因。
你可以使用一个叫做 linter 的工具来检查有没有未使用的模块。