PEP 8说:
- 导入总是放在文件的顶部,就在任何模块注释和文档字符串之后,以及模块全局变量和常量之前。
有时,我违反了PEP8。有时我会在函数中导入东西。作为一般规则,如果导入仅在单个函数中使用,则执行此操作。
任何意见?
编辑(我觉得导入函数的原因可能是一个好主意):
主要原因:它可以使代码更清晰。
from m import xxx
时,这是一个更大的问题。在功能中看到m.xxx
可能会告诉我更多。取决于m
是什么:它是一个着名的顶级模块/包(import m
)?或者它是一个子模块/包(from a.b.c import m
)?从长远来看,我认为你会很高兴你的大部分导入都位于文件的顶部,这样你就可以一目了然地看出你的模块需要导入的复杂程度。
如果我将新代码添加到现有文件中,我通常会在需要的地方进行导入,然后如果代码保持不变,我会通过将导入行移动到文件顶部来使事情变得更加永久。
另外一点,我更喜欢在任何代码运行之前得到一个ImportError
异常 - 作为一个完整性检查,所以这是在顶部导入的另一个原因。
我使用pyChecker
来检查未使用的模块。
在这方面,我有两次违反PEP 8:
import pdb; pdb.set_trace()
这很方便b / c我不想把import pdb
放在我可能要调试的每个模块的顶部,并且当我删除断点时很容易记住删除导入。在这两种情况之外,将所有内容放在首位是个好主意。它使依赖关系更加清晰。
以下是我们使用的四个导入用例
import
(以及from x import y
和import x as y
)位于顶部import settings
if setting.something:
import this as foo
else:
import that as foo
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编写的复杂数据结构。它有点像腌制的数据,除非我们手工腌制。
这也或多或少地位于模块的顶部以下是我们如何使代码更清晰:
要记住一件事:不必要的进口可能会导致性能问题。因此,如果这是一个经常调用的函数,那么最好只将导入放在顶部。当然这是一个优化,所以如果有一个有效的案例表明在函数内部导入比在文件顶部导入更清楚,那么在大多数情况下这会胜过性能。
如果你正在做IronPython,我被告知最好导入内部函数(因为在IronPython中编译代码可能很慢)。因此,您可以通过导入内部函数来获得一种方法。但除此之外,我认为打击惯例是不值得的。
作为一般规则,如果导入仅在单个函数中使用,则执行此操作。
我想提出的另一点是,这可能是一个潜在的维护问题。如果添加使用以前仅由一个函数使用的模块的函数会发生什么?你会记得将导入添加到文件顶部吗?或者您要扫描每个功能进口?
FWIW,有些情况下导入函数内部是有意义的。例如,如果要在cx_Oracle中设置语言,则需要在导入之前设置NLS_
LANG环境变量。因此,您可能会看到如下代码:
import os
oracle = None
def InitializeOracle(lang):
global oracle
os.environ['NLS_LANG'] = lang
import cx_Oracle
oracle = cx_Oracle
对于自我测试的模块,我之前已经破坏了这个规则。也就是说,它们通常只用于支持,但我为它们定义了一个main,这样如果你自己运行它们就可以测试它们的功能。在这种情况下,我有时会在main中导入getopt
和cmd
,因为我希望有人在阅读代码时明白这些模块与模块的正常操作无关,并且仅包含在测试中。
来自关于loading the module twice的问题 - 为什么不两者?
脚本顶部的导入将指示依赖项和函数中的另一个导入,使此函数更具原子性,同时看似不会导致任何性能劣势,因为连续导入很便宜。
只要它是import
而不是from x import *
,你应该把它们放在顶部。它只为全局命名空间添加一个名称,并且您坚持使用PEP 8.另外,如果您以后需要它在其他地方,则不必移动任何东西。
这没什么大不了的,但由于几乎没有什么区别,我建议做PEP 8所说的。
看看sqlalchemy中使用的替代方法:依赖注入:
@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
#...
query.Query(...)
注意导入的库是如何在装饰器中声明的,并作为参数传递给函数!
这种方法使代码更清晰,并且比import
语句快4.5倍!
基准:https://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796