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
:
#!/usr/bin/env python
import package
package.go()
package/__init__.py
:
from __future__ import absolute_import
import logging
from .logging import config
def go():
config(level=logging.DEBUG)
logging.getLogger().debug('this is a test')
package/logging.py
:
from __future__ import absolute_import
import logging
def config(*args, **kwargs):
return logging.basicConfig(*args, **kwargs)
我收到以下错误:
$ ./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
包然后再次重新绑定名称。
使用以下代码:
foo.py
:#!/usr/bin/env python import package package.go()
package/__init__.py
:from __future__ import absolute_import import logging from .logging import config def go(): config(level=logging.DEBUG) logging.getLogger().debug('this is a test')
package/logging.py
:from __future__ import absolute_import import logging def config(*args, **kwargs): return logging.basicConfig(*args, **kwargs)
我收到以下错误:
$ ./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
包然后再次重新绑定名称。