导入函数是pythonic吗?
PEP 8说:
- 导入总是放在文件的顶部,在任何模块注释和文档string之后,在模块全局variables和常量之前。
在发生时,我违反了PEP 8.有时我在函数内部导入东西。 作为一般规则,如果有一个导入只在一个函数中使用,我会这样做。
有什么意见?
编辑(我觉得在function导入的原因可以是一个好主意):
主要原因:可以使代码更清晰。
- 当看一个函数的代码时,我可能会问自己:“什么是函数/类xxx?” (xxx在函数内部使用)。 如果我把所有的input都放在模块的顶部,我必须去看那里确定xxx是什么。
from m import xxx
使用时,这是更多的问题。 在函数中看到m.xxx
可能会告诉我更多。 取决于m
是什么:它是一个众所周知的顶级模块/包(import m
)? 或者它是一个子模块/包(from abc import m
)? - 在某些情况下,使用xxx附近的附加信息(“什么是xxx?”)可以使得该function更易于理解。
从长远来看,我认为你会感激你的大部分导入在文件的顶部,这样你可以一目了然地告诉你需要导入的模块有多复杂。
如果我将新代码添加到现有文件中,我通常会在需要的地方进行导入,然后如果代码保留,我会通过将导入线移动到文件顶部来使事情更加永久。
还有一点,我更喜欢在任何代码运行之前得到一个ImportErrorexception – 作为一个完整的检查,所以这是导入顶部的另一个原因。
我使用pyChecker来检查未使用的模块。
在这方面有两次我违反了PEP 8:
- 循环导入:模块A导入模块B,但模块B中的东西需要模块A(尽pipe这通常是我需要重构模块以消除循环依赖的标志)
- 插入一个pdb断点:
import pdb; pdb.set_trace()
import pdb; pdb.set_trace()
这是方便的b / c我不想把import pdb
放在每个模块的顶部,我可能想要debugging,并且很容易记住当我删除断点时删除导入。
除了这两种情况之外,把所有东西都放在最上面是个好主意。 它使依赖关系更清晰。
以下是我们使用的四个导入用例
-
import
(from x import y
和import x as y
)在顶部 -
select导入。 在顶部。
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
-
dynamic导入。 到目前为止,我们只有一个例子。
import settings module_stuff = {} module= __import__( settings.some_module, module_stuff ) x = module_stuff['x']
请注意,这种dynamic导入不会引入代码,但会带来用Python编写的复杂数据结构。 除了我们用手腌制之外,它有点像一个腌制的数据。
这也是,或多或less,在一个模块的顶部
以下是我们所做的使代码更清晰:
-
保持模块简短。
-
如果我把所有的input都放在模块的顶部,我必须去那里看看是什么名字。 如果模块很短,那很容易做到。
-
在某些情况下,使用名称附近的额外信息可以使该function更易于理解。 如果模块很短,那很容易做到。
有一件事要记住:不必要的import可能会导致性能问题。 所以如果这是一个会频繁调用的函数,那么最好把导入放在最前面。 当然这是一个优化,所以如果有一个有效的例子来说明,在函数内部导入比在文件顶部导入更清晰,那么在大多数情况下,性能是胜于性能的。
如果你在做IronPython,我被告知最好导入里面的函数(因为在IronPython中编译代码可能会很慢)。 因此,您可能可以通过导入内部函数来获得方法。 但除此之外,我认为这是不值得与常规打交道的。
作为一般规则,如果有一个导入只在一个函数中使用,我会这样做。
另一点我想说的是,这可能是一个潜在的维护问题。 如果添加一个使用之前仅由一个函数使用的模块的函数,会发生什么情况? 你会记得将导入添加到文件的顶部? 还是你要扫描每一个importfunction?
FWIW,有些情况下在函数内部导入是有意义的。 例如,如果要在cx_Oracle中设置语言,则需要在导入之前设置NLS _
LANG环境variables。 因此,你可能会看到这样的代码:
import os oracle = None def InitializeOracle(lang): global oracle os.environ['NLS_LANG'] = lang import cx_Oracle oracle = cx_Oracle
我已经打破了这个规则自我testing的模块。 也就是说,它们通常只是用于支持,但是我为它们定义了一个main,所以如果你自己运行它们,你可以testing它们的function。 在这种情况下,我有时会将getopt
和cmd
导入到main中,因为我希望读取代码的人清楚,这些模块与模块的正常运行无关,只是包含在testing中。
只要它是import
而不是from x import *
,你应该把它们放在最前面。 它只在全局名称空间中添加一个名称,并且坚持使用PEP 8.另外,如果以后需要它,则不必移动任何东西。
这没什么大不了的,但是因为几乎没有什么区别,所以我build议按照PEP 8的说法做。
来自两次加载模块的问题 – 为什么不是两个?
脚本顶部的导入将指示依赖关系,而函数中的另一个导入使得此函数更加primefaces化,而看起来不会导致任何性能劣势,因为连续导入是便宜的。