relative and absolute imports with the same name causing "AttributeError: 'module' object has no attribute ..."

relative and absolute imports with the same name causing "AttributeError: 'module' object has no attribute ..."

使用以下代码:

我收到以下错误:

$ ./foo.py
Traceback (most recent call last):
  File "./foo.py", line 3, in <module>
    package.go()
  File "/tmp/test/package/__init__.py", line 5, in go
    config(level=logging.DEBUG)
AttributeError: 'module' object has no attribute 'DEBUG'

好像 from .logging import config 行正在将 .logging 导入为 logging,尽管我不希望这样。

如果我交换 package/__init__.py 中的导入行,使其看起来像这样:

from __future__ import absolute_import
from .logging import config
import logging
def go():
    config(level=logging.DEBUG)
    logging.getLogger().debug('this is a test')

然后就可以了:

$ ./foo.py
DEBUG:root:this is a test

原来的版本有什么问题?或者这是 Python 2.7.8 中的错误?

包内的模块一旦导入,就会设置为其父包的属性。

在您导入 .logging 的那一刻,它被添加到 package 命名空间,例如在 package 目录中 __init__globals() 词典中。

通过交换导入,您又用顶级包替换了 __init__ 模块命名空间中的 logging 全局;首先导入子模块并将其添加到全局变量中,然后导入 logging 包,替换全局变量。

演示:

$ mkdir package
$ cat > package/__init__.py << EOF
> from __future__ import absolute_import
> from .logging import foo
> print globals().keys()
> print logging
> import logging
> print globals().keys()
> print logging
> EOF
$ cat > package/logging.py << EOF
> foo = 'bar'
> print 'imported package.logging'
> EOF
$ python -c 'import package'
imported package.logging
['logging', '__builtins__', '__file__', 'absolute_import', '__package__', '__path__', '__name__', 'foo', '__doc__']
<module 'package.logging' from 'package/logging.pyc'>
['logging', '__builtins__', '__file__', 'absolute_import', '__package__', '__path__', '__name__', 'foo', '__doc__']
<module 'logging' from '/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py'>

.logging 包中导入 foo 后,logging 全局变量就出现了。导入顶级 logging 包然后再次重新绑定名称。