Python中的好习惯还是坏习惯:在文件中间导入

72 投票
9 回答
36802 浏览
提问于 2025-04-15 13:12

假设我有一个比较长的模块,但只需要用到一个外部模块或方法一次。

在模块的中间导入这个方法或模块可以吗?

还是说,import语句应该只放在模块的开头部分。

举个例子:

import string, pythis, pythat
...
...
...
...
def func():
     blah
     blah 
     blah
     from pysomething import foo
     foo()
     etc
     etc 
     etc
...
...
...

请解释一下你的答案,并附上相关的PEP或其他相关资料的链接

9 个回答

20

大家都提到了PEP(Python增强提案),但还要注意不要在关键代码中间放置导入语句。至少在Python 2.6版本中,如果一个函数里有导入语句,会需要更多的字节码指令。

>>> def f():
    from time import time
    print time()

>>> dis.dis(f)
  2           0 LOAD_CONST               1 (-1)
              3 LOAD_CONST               2 (('time',))
              6 IMPORT_NAME              0 (time)
              9 IMPORT_FROM              0 (time)
             12 STORE_FAST               0 (time)
             15 POP_TOP             

  3          16 LOAD_FAST                0 (time)
             19 CALL_FUNCTION            0
             22 PRINT_ITEM          
             23 PRINT_NEWLINE       
             24 LOAD_CONST               0 (None)
             27 RETURN_VALUE

>>> def g():
    print time()

>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (time)
              3 CALL_FUNCTION            0
              6 PRINT_ITEM          
              7 PRINT_NEWLINE       
              8 LOAD_CONST               0 (None)
             11 RETURN_VALUE  
41

在2001年,Python的邮件列表上对此话题进行了详细讨论:

https://mail.python.org/pipermail/python-list/2001-July/071567.html

以下是讨论中提到的一些理由。来自Peter Hansen的观点,他列出了三个不把所有导入放在文件顶部的理由:

在函数中导入的可能原因:

  1. 可读性:如果某个导入只在一个函数中需要,而且这个需求很可能不会改变,那么把它放在那个函数里会更清晰、更整洁。

  2. 启动时间:如果你不把导入放在函数定义外面,那么当你的模块被其他模块首次导入时,这些导入不会执行,而是等到某个函数被调用时才会执行。这样可以延迟导入的开销(如果这些函数可能根本不会被调用,甚至可以避免导入)。

  3. 总会有比我们想到的更多的理由。

Just van Rossum也补充了一个第四个理由:

  1. 开销:如果一个模块导入了很多其他模块,而实际上只有少数几个会被用到。这和“启动时间”的理由类似,但更进一步。如果一个使用你模块的脚本只用到一小部分功能,这样可以节省不少时间,尤其是当那些可以避免的导入还导入了很多模块时。

还有一个第五个理由是,局部导入可以避免循环导入的问题。

欢迎你去阅读那个讨论串,了解更全面的内容。

66

PEP 8 的作者明确指出:

导入的内容总是放在文件的最上面,紧接着模块的注释和文档字符串之后,然后再是模块的全局变量和常量。

PEP 8 应该成为任何“内部”风格指南的基础,因为它总结了核心 Python 团队认为最有效的编程风格(当然,个别意见会有所不同,就像其他语言一样,但大家达成共识的 BDFL 也同意 PEP 8)。

撰写回答