使用以下代码:
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中的错误?
答案 0 :(得分:3)
包中的模块一旦导入,就会在其父包中设置为属性。
您导入.logging
的那一刻,它会被添加到package
命名空间,例如在globals()
目录中__init__
的{{1}}字典中。
通过交换导入,您再次将package
模块命名空间中的logging
全局替换为顶级包;首先导入子模块并将其添加到全局变量中,然后导入__init__
包,替换为全局。
演示:
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'>
包中导入foo
后,.logging
全局显示。导入顶级logging
包然后再次重新绑定该名称。