导致"属性错误:'模块'对象没有属性..."

时间:2015-01-18 03:10:23

标签: python python-2.7 python-import

使用以下代码:

  • 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中的错误?

1 个答案:

答案 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包然后再次重新绑定该名称。