如何防止Python模块自我导入?

16 投票
3 回答
5543 浏览
提问于 2025-04-15 16:41

比如说,我想为另一个项目做一个sql alchemy的插件。我想把这个模块命名为sqlalchemy.py。问题是,这样会导致我无法导入sqlalchemy

#sqlalchemy.py
import sqlalchemy 

这样会让这个模块自己导入自己。我试过这样做,但似乎不太管用:

import sys
#Remove the current directory from the front of sys.path
if not sys.path[0]:
    sys.path.pop(0)
import sqlalchemy

有没有什么建议呢?

3 个回答

2

你可能是因为在交互式解释器和从文件运行代码时的差异而遇到了问题。去掉对 sys.path[0] 是否为空的检查(从文件运行时,它是不会为空的),这样导入就应该能像你想的那样正常工作了。

$ more sqlalchemy.py
import sys
print sys.path[0]
sys.path.pop(0)
import sqlalchemy
print sqlalchemy.__file__
$ python sqlalchemy.py 
/Users/nad
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/sqlalchemy/__init__.pyc
$ python
Python 2.6.4 (r264:75706, Oct 28 2009, 20:34:51) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys; print repr(sys.path[0])
''

补充说明:如果你的主模块是 sqlalchemy.py,那么上述内容适用。如果你的模块是被其他模块导入的,你还需要像Alex所说的那样修改 sys.modules

2

不要把它命名为 sqlalchemy.py 吗?

说真的,我觉得这就是绝对导入(absolute imports)要解决的问题。在 Python 2.5 中,这种情况应该是不会发生的,但我可能错了。

14

编辑: 由于提问者现在提到问题是相对导入优先于绝对导入,解决这个特定问题的最简单方法是在模块开头加上 from __future__ import absolute_import,这样就能改变这种“优先级”或顺序。

接下来,仍然需要注意两个绝对导入冲突的问题(虽然这似乎不是提问者目前面临的情况...):

一旦你导入了一个名为 x 的模块,这个模块就会被记录在 sys.modules['x'] 中——你所做的更改 sys.path 并不会影响 sys.modules。你还需要直接修改 sys.modules

例如,考虑以下情况:

$ cat a/foo.py
print __file__; import sys; sys.path.insert(0, "b"); del sys.modules["foo"]; import foo
$ cat b/foo.py
print __file__
$ python2.5 -c'import sys; sys.path.insert(0, "a"); import foo'
a/foo.py
b/foo.py

(再次运行时会使用并显示 .pyc 文件,而不是 .py 文件,当然。)

这并不是最干净的做法,当然这样一来,原来的 foo 模块就无法从外部访问了(因为它在 sys.modules 中的条目被替换掉了),但根据你的具体需求,你可以做一些更脆弱的操作(在删除之前把 sys.modules["foo"] 存放到某个地方,导入另一个 foo 后把那个模块放到别的地方,然后再恢复原来的 sys.modules["foo"] ——等等等等)。当然,避免名称冲突通常会比这样处理要简单得多;-)。

撰写回答