Python 条件“模块对象没有属性”个人包裹错误与循环导入问题不同
当尝试使用我创建的包层次结构时,我收到“模块对象没有属性...”错误。该错误让人想起循环导入时遇到的错误(即模块 a 导入 b 和模块 b导入 a),但我在这里看不到这个问题。我已经浏览了很多有类似错误的帖子,但我看到的解释都不太合适。
这是在 python 2.7.1 和 python 2.4.3 中看到的。
我浇过水 考虑以下
层次结构(参见下面的代码):
alpha
alpha/__init__.py
alpha/bravo
alpha/bravo/__init__.py
alpha/bravo/charlie.py
alpha/bravo/delta.py
alpha/bravo/echo.py
charlie 模块导入 echo,而 echo 又导入 delta 如果 alpha/bravo/__init__.py (如 alpha/__init__.py)基本上是空白的,则 a脚本可以做:
import alpha.bravo.charlie
如果我尝试在 alpha/bravo/__init__.py 中导入 alpha.bravo.charlie ,问题就会出现(我认为我可以在那里显示相关的类/方法,并且脚本会执行“导入” alpha
代码:
alpha/__init__.py
(blank)
/bravo/__init__.py
import alpha.bravo.charlie
alpha/bravo/charlie.py
import alpha.bravo.echo
def charlie_foo(x): return str(x)
def charlie_bar(x): return alpha.bravo.echo.echo_biz()
alpha/bravo/delta.py
def delta_foo(x): return str(x)
alpha/bravo/echo.py
import alpha.bravo.delta
print alpha.bravo.delta.delta_foo(1)
def echo_biz(): return 'blah'
如果我尝试:
python -c 'import alpha.bravo'
我得到:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/__init__.py", line 1, in <module>
import alpha.bravo.charlie
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/charlie.py", line 1, in <module>
import alpha.bravo.echo
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/echo.py", line 2, in <module>
print alpha.bravo.delta.delta_foo(1)
AttributeError: 'module' object has no attribute 'bravo'
但是,如果我注释掉 alpha/bravo/__init__.py 中的导入行,那么一切似乎都可以:
python -c 'import alpha.bravo'
python -c 'import alpha.bravo.charlie'
1
此外,如果我使用上面相同的代码(包括导入行alpha/bravo/__init__.py),但编辑所有内容以排除层次结构的“alpha”级别,它似乎工作正常。
所以层次结构现在只是:
bravo
bravo/__init__.py
bravo/charlie.py
bravo/delta.py
bravo/echo.py
我将所有带有“alpha.bravo.*”的行更改为“bravo.*”
然后没问题:
python -c 'import bravo'
1
我已经能够解决这个问题,但我仍然想了解它。谢谢。
I'm getting a 'module object has no attribute ..." error when trying to use a package heirarchy I created. The error is reminiscant of the error you get when there is a circular import (i.e. module a imports b and module b imports a), but I can't see that issue here. I've gone through many posts with a similar error, but none of the explanations I saw quite fit.
This was seen with python 2.7.1 and python 2.4.3.
I've watered it down to the following example:
Consider the following heirarchy (see code below):
alpha
alpha/__init__.py
alpha/bravo
alpha/bravo/__init__.py
alpha/bravo/charlie.py
alpha/bravo/delta.py
alpha/bravo/echo.py
The module charlie imports echo which in turn imports delta. If the alpha/bravo/__init__.py (like alpha/__init__.py) is essentially blank, a script can do:
import alpha.bravo.charlie
The problem surfaces if I try to import alpha.bravo.charlie in alpha/bravo/__init__.py (with the thinking I could surface relevant classes/methods there, and a script would do 'import alpha.bravo').
Code:
alpha/__init__.py
(blank)
alpha/bravo/__init__.py
import alpha.bravo.charlie
alpha/bravo/charlie.py
import alpha.bravo.echo
def charlie_foo(x): return str(x)
def charlie_bar(x): return alpha.bravo.echo.echo_biz()
alpha/bravo/delta.py
def delta_foo(x): return str(x)
alpha/bravo/echo.py
import alpha.bravo.delta
print alpha.bravo.delta.delta_foo(1)
def echo_biz(): return 'blah'
If I try:
python -c 'import alpha.bravo'
I get:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/__init__.py", line 1, in <module>
import alpha.bravo.charlie
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/charlie.py", line 1, in <module>
import alpha.bravo.echo
File "/home/kmkc980/svn/working/azcif/python/lib/alpha/bravo/echo.py", line 2, in <module>
print alpha.bravo.delta.delta_foo(1)
AttributeError: 'module' object has no attribute 'bravo'
But, if I comment out the import line in alpha/bravo/__init__.py, then all seems OK:
python -c 'import alpha.bravo'
python -c 'import alpha.bravo.charlie'
1
Moreover, if I use the same code above (including the import line in alpha/bravo/__init__.py), but edit everything to exclude the 'alpha' level of the hierarchy, it seems to work fine.
So the hierarchy is now just:
bravo
bravo/__init__.py
bravo/charlie.py
bravo/delta.py
bravo/echo.py
and I change all the lines with "alpha.bravo.*" to "bravo.*"
Then no problem:
python -c 'import bravo'
1
I've been able to work around the issue, but I'd still like to understand it. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这就是原因
(我相信,这主要得到 http://docs.python.org/faq/programming.html#how-can-i-have-modules-that-mutually-import-each-other< /a>)
当Python解释器遇到
import abc
形式的一行,它会执行以下步骤。在伪 python 中:这里有三个要点:
模块 a、ab 和 abc 会按顺序导入(如果尚未导入)
模块在其父级命名空间中不存在,直到完全完成导入为止。因此,在完全导入
ab
之前,模块a
不具有b
属性。无论您的模块链有多深,即使您
导入 abcdefg
,您的代码也只会将一个符号添加到其命名空间中:a
.因此,当您稍后尝试运行
abcdefgsome_function()
时,解释器必须沿着模块链一路遍历才能到达该方法。这是发生的事情
根据您发布的代码,问题似乎出在
alpha/bravo/echo/__init__.py
中的 print 语句中。解释器到达那里时所做的事情大致如下:在 sys.modules 中为 alpha 设置一个空模块对象
运行 alpha/__init__.py 中的代码(请注意,此时 dir(alpha) 不会包含 'bravo')
在 sys.modules 中为 alpha.bravo 设置一个空模块对象
运行alpha/bravo/__init__.py中的代码:
4.1 在 sys.modules 中为 alpha.bravo.charlie 设置一个空模块对象
4.2 运行 alpha/bravo/charlie/__init__.py 中的代码:
4.2.1 设置sys.modules 4.2.2 中 alpha/bravo/echo 的空模块对象
运行 alpha/bravo/echo/__init__.py 中的代码:
4.2.2.1 在 sys.modules 中为 alpha/bravo/delta 设置一个空模块对象
4.2.2.2 运行 alpha/bravo/delta/__init__.py 中的代码 -- 这样就完成了,所以 'delta' 被添加到 'alpha。布拉沃的符号。
4.2.2.3 将“alpha”添加到 echo 的符号中。这是
导入 alpha.bravo.delta
的最后一步。此时,如果我们对 sys.modules 中的所有模块调用 dir(),我们将看到:
'alpha':
['__builtins__', '__doc__', '__file__', '__name__ ', '__package__', '__path__', '__return__']
(这本质上是空的)' alpha.bravo':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'delta']
(delta 已经完成导入,所以就在这里)'alpha.bravo.charlie':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
(空)'alpha.bravo .delta':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__', 'delta.foo']
(这是唯一已完成的)'alpha.bravo.echo':
['__builtins__', '__doc__', '__file__'、'__name__'、'__package__'、'__path__'、'__return__'、'alpha']
现在Intepreter 继续执行 alpha/bravo/echo/__init__.py,遇到
print 行alpha.bravo.delta.delta_foo(1)
。这开始了这个序列:这与循环导入期间发生的情况相同 - 模块尚未完成初始化,因此符号表未完全更新,并且属性访问失败。
如果您要将 echo/__init__.py 中的有问题的行替换为:
这可能会起作用,因为 delta 已完全初始化。但在 bravo 完成之前(在 echo 和 charlie 返回之后),alpha 的符号表不会更新,并且您将无法通过它访问 bravo。
另外,正如@Rik Poggi所说,如果您将导入行更改为
Then,那就可以了。在这种情况下,因为
from alpha.bravo.delta
直接转到 sys.modules 字典,而不是从 alpha 遍历到 bravo 再到 delta,所以它可以从 delta 模块获取函数并将其分配给一个局部变量,您可以毫无问题地访问它。Here's the why
(This is, I believe, mostly supported by the explanation at http://docs.python.org/faq/programming.html#how-can-i-have-modules-that-mutually-import-each-other)
When the Python interpreter encounters a line of the form
import a.b.c
, it runs through the following steps. In pseudo-python:There are three important points here:
The modules a, a.b, and a.b.c get imported in order, if they haven't been imported already
A module does not exist in its parent's namespace until it has completely finished being imported. So module
a
does not have ab
attribute untila.b
has been imported completely.No matter how deep your module chain is, even if you
import a.b.c.d.e.f.g
, your code only gets one symbol added to its namespace:a
.So when you later try to run
a.b.c.d.e.f.g.some_function()
, the interpreter has to traverse all the way down the chain of modules to get to that method.Here's what is happening
Based on the code that you have posted, the problem seems to lie in the print statement in
alpha/bravo/echo/__init__.py
. What the interpreter has done by the time it gets there is roughly this:Set up an empty module object for alpha in sys.modules
Run the code in alpha/__init__.py (Note that dir(alpha) won't contain 'bravo' at this point)
Set up an empty module object for alpha.bravo in sys.modules
Run the code in alpha/bravo/__init__.py:
4.1 Set up an empty module object for alpha.bravo.charlie in sys.modules
4.2 Run the code in alpha/bravo/charlie/__init__.py:
4.2.1 Set up an empty module object for alpha/bravo/echo in sys.modules
4.2.2 Run the code in alpha/bravo/echo/__init__.py:
4.2.2.1 Set up an empty module object for alpha/bravo/delta in sys.modules
4.2.2.2 Run the code in alpha/bravo/delta/__init__.py -- This finishes, so 'delta' is added to 'alpha.bravo's symbols.
4.2.2.3 Add 'alpha' to echo's symbols. This is the last step in
import alpha.bravo.delta
.At this point, if we call dir() on all of the modules in sys.modules, we will see this:
'alpha':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__']
(this is essentially empty)'alpha.bravo':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'delta']
(delta has finished being imported, so it's here)'alpha.bravo.charlie':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
(empty)'alpha.bravo.delta':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__', 'delta.foo']
(This is the only one that has completed)'alpha.bravo.echo':
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__return__', 'alpha']
Now the intepreter continues with alpha/bravo/echo/__init__.py, where it encounters the line
print alpha.bravo.delta.delta_foo(1)
. That starts this sequence:alpha
-- this returns the still-emptyalpha
module.alpha.bravo
isn't finished being initialized yet, so bravo hasn't been inserted into alpha's symbol table.This is the same thing that happens during a circular import -- the module isn't finished being initialized, so the symbol table isn't completely updated, and attribute access fails.
If you were to replace the offending line in echo/__init__.py with this:
That would probably work, since delta is completely initialized. But until bravo is complete (after echo and charlie return), the symbol table for alpha won't be updated, and you won't be able to access bravo through it.
Also, as @Rik Poggi says, if you change the import line to
Then that will work. In this case, because
from alpha.bravo.delta
goes right to the sys.modules dict, rather than traversing from alpha to bravo to delta, it can get the function from the delta module and assign it to a local variable, which you can then access without any trouble.使用相对导入可能会有所帮助,而不是使用绝对导入。
即
alpha/bravo/_init_.py
应该是
否则,它可能是循环导入。即,如果您从 charlie 导入 alpha.bravo.charlie,则意味着
所有内容均已加载(或者更确切地说,由于它们已加载而无法这样做)。
这可能会导致您所看到的问题。
Instead of using absolute imports, it might help to use relatives.
i.e.
alpha/bravo/_init_.py
should be
Otherwise, it probably is a circular import. i.e. if you import alpha.bravo.charlie from charlie, that means
All are loaded (or rather, prevented from doing so since they're already loaded).
That might cause the problem you're seeing.