如何防止模块被重复导入?

37 投票
3 回答
28801 浏览
提问于 2025-04-15 17:48

在写Python模块的时候,有没有办法防止它被客户端代码重复导入呢?就像C/C++的头文件那样:

#ifndef XXX
#define XXX
...
#endif

非常感谢!

3 个回答

23

导入的模块会被缓存,也就是说它们只会运行一次。之后再导入同样的模块,只需要花一点时间去查找一下已经导入的模块就可以了。

28

正如其他回答所提到的,Python 通常在遇到第二次导入同一个模块时,不会重新加载这个模块。相反,它会从 sys.modules 中返回一个缓存的版本,而不会执行模块中的任何代码。

不过,有几个需要注意的陷阱:

  • 把主模块当作普通模块导入,实际上会在不同的名称下创建两个相同模块的实例。

    这是因为在程序启动时,主模块会被设置为名称 __main__。所以,当你把它当作普通模块导入时,Python 并没有在 sys.modules 中找到它,于是又重新导入了一次,但这次用的是它的正确名称。

    假设有一个文件 /tmp/a.py,内容如下:

    # /tmp/a.py
    import sys
    
    print "%s executing as %s, recognized as %s in sys.modules" % (__file__, __name__, sys.modules[__name__])
    import b
    

    另一个文件 /tmp/b.py 只包含一条导入语句来导入 a.pyimport a)。
    执行 /tmp/a.py 会得到以下输出:

    root@machine:/tmp$ python a.py
    a.py executing as __main__, recognized as <module '__main__' from 'a.py'> in sys.modules
    /tmp/a.pyc executing as a, recognized as <module 'a' from '/tmp/a.pyc'> in sys.modules
    

    因此,最好保持主模块的功能尽量简单,把大部分功能导出到外部模块,正如这里所建议的那样。

  • 这个回答还提到了另外两种可能的情况:

    1. 使用 sys.path 中不同的条目来导入稍微不同的导入语句,结果却指向同一个模块。
    2. 在之前的导入失败了一半后,再次尝试导入同一个模块。
55

在Python中,模块不会被多次导入。也就是说,如果你运行两次导入同一个模块,它不会重新加载这个模块。如果你想让它重新加载,就需要使用reload这个命令。下面是一个示例。

foo.py是一个模块,里面只有一行代码:

print("I am being imported")

接下来是多次尝试导入的屏幕记录。

   >>> import foo
   Hello, I am being imported
   >>> import foo # Will not print the statement
   >>> reload(foo) # Will print it again
   Hello, I am being imported

撰写回答