在函数内导入是 Pythonic 吗?

156 投票
10 回答
68015 浏览
提问于 2025-04-15 12:24

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

这里有四种我们使用的导入方式

  1. import(还有 from x import yimport x as y)通常放在文件的最上面

  2. 导入的选择。也放在最上面。

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
    
  3. 条件导入。通常用于处理 JSON、XML 等库。也放在最上面。

    try:
        import this as foo
    except ImportError:
        import that as foo
    
  4. 动态导入。目前我们只有一个例子。

    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 的工具来检查有没有未使用的模块。

撰写回答