子包中绝对导入失败,因包名与标准库冲突

7 投票
1 回答
2573 浏览
提问于 2025-04-15 17:20

基本上,我有一个子包,它的名字和标准库的包(“logging”)是一样的。我希望无论我怎么运行它,都能绝对导入标准库的那个包,但当我在父包中时,这个操作失败了。

这看起来像是一个错误,或者是新“绝对导入”支持(从Python 2.5开始)的一种未记录的行为。我在2.5和2.6版本中都试过。

包的结构如下:

foo/
    __init__.py
    logging/
        __init__.py

foo/__init__.py 中,我们导入了自己的 logging 子包:

from __future__ import absolute_import
from . import logging as rel_logging
print 'top, relative:', rel_logging

foo/logging/__init__.py 中,我们想要导入标准库的 logging 包:

from __future__ import absolute_import
print 'sub, name:', __name__

import logging as abs_logging
print 'sub, absolute:', abs_logging

注意:包含 foo 的文件夹在 sys.path 中。


当从外部或上层导入 foo 时,输出是预期的:

c:\> python -c "import foo"
sub, name: foo.logging
sub, absolute: <module 'logging' from 'c:\python26\lib\logging\__init__.pyc'>
top, relative: <module 'foo.logging' from 'foo\logging\__init__.pyc'>

所以在子包中的绝对导入能够找到标准库的包,正如我们所希望的那样。

但是当我们在 foo 文件夹内时,情况就不同了:

c:\foo>\python25\python -c "import foo"
sub, name: foo.logging
sub, name: logging
sub, absolute: <module 'logging' from 'logging\__init__.pyc'>
sub, absolute: <module 'logging' from 'logging\__init__.pyc'>
top, relative: <module 'foo.logging' from 'c:\foo\logging\__init__.pyc'>

对于“sub, name”的双重输出显示,我自己叫“logging”的子包又导入了一次自己,并且即使“absolute_import”已启用,它也找不到标准库的“logging”包。

我的使用场景是,我希望能够在任何当前目录下都能使用、测试这个包。把名字从“logging”改成其他名字虽然可以解决问题,但这并不是一个理想的办法,而且无论如何,这种行为似乎与绝对导入应该如何工作的描述不符。

有没有人知道这是怎么回事?这是我的错误还是Python的错误?或者这种行为是否在某些文档中有说明?

编辑:gahooa的回答清楚地指出了问题所在。这里展示了一个粗略的解决方法,证明了这个问题:

c:\foo>python -c "import sys; del sys.path[0]; import foo"
sub, name: foo.logging
sub, absolute: <module 'logging' from 'c:\python26\lib\logging\__init__.pyc'>
top, relative: <module 'foo.logging' from 'c:\foo\logging\__init__.pyc'>

1 个回答

9

sys.path[0] 默认是 '',这表示“当前目录”。所以如果你在一个包含 logging 的文件夹里,系统会优先选择这个文件夹。

我最近遇到过这个问题,直到我意识到我其实是在那个文件夹里,sys.path 首先会查看我当前的文件夹,然后才会去标准库里找。

撰写回答