Python包导入混乱

时间:2015-03-26 18:40:42

标签: python python-2.7 python-import

如果我的目录结构如下:

.
└── pkg
    ├── A.py
    ├── B.py
    ├── C.py
    ├── __init__.py
    └── test
        └── script.py

script.py包含的位置:

import pkg.B
import pkg.A

print pkg.A.test()

A.py

import pkg.C

def test():
    return pkg.B.test()

B.py

def test():
    return 'AAAA'

C.py

def test3():
    return 'C.test3'

并且__init__.py为空。

如果A.py导入pkg.C,则代码有效。如果我注释掉那个导入,那么它失败了:

Traceback (most recent call last):
  File "pkg/test/script.py", line 9, in <module>
    print pkg.A.test()
  File "/Users/X/Desktop/importtest/pkg/A.py", line 4, in test
    return pkg.B.test()
NameError: global name 'pkg' is not defined
只要在import pkg.C中导入import pkg

pkg.B更改为仅script.py

如果我从pkg.B注释掉script.py的导入,那么如果我import pkgimport pkg.C A.py,那么它就不会有所作为我收到一个错误:

Traceback (most recent call last):
  File "pkg/test/script.py", line 10, in <module>
    print pkg.A.test()
  File "/Users/X/Desktop/importtest/pkg/A.py", line 4, in test
    return pkg.B.test()
AttributeError: 'module' object has no attribute 'B' 

这是我期望的行为。

所以基本问题是,如果在pkg.B.test()中导入A.pypkg.B导入pkg.Bscript.py可以A.py访问{{1}} }和{{1}}导入其他子模块?

我还不清楚这里工作的确切机制是什么。对于描述导入逻辑的好文章的解释或指示将是最受欢迎的。

1 个答案:

答案 0 :(得分:1)

这个问题有点陈旧,但在遇到类似问题时我偶然发现了它。这就是我所理解的事情:

模块导入一次

我们首先需要了解的是,modules are loaded only once!这意味着,例如,如果我们有:

X.py

import Z
import Y
blah blah

Y.py

import Z
blah bloo

运行X.py将为我们提供以下内容:

  1. 模块Z将加载到第一行。
  2. 将运行模块Y(作为import Y的结果)。
  3. 虽然import Z是模块Y中的第一行,但模块Z是。{ 没有再次加载。
  4. 注意:无论如何,模块是否已加载,模块的名称导入的进入当前命名空间,使其可以访问但它们都引用相同的模块对象!!

    导入子模块

    导入子模块(例如pkg.A)时,实质上是加载包pkg __init__.py模块,另外,加载A.py模块。但是你正在做的是将子模块作为属性添加到包的模块。即:

    >>> import pkg
    >>> hasattr(pkg, 'A')
    False
    

    重启Python会话后:

    >>> import pkg.A
    >>> hasattr(pkg, 'A')
    True
    

    将各个部分放在一起

    因此,在script.py执行import pkg.B时,pkg模块已加载,并且属性B已添加到其“{1}}中。模块对象。当A.py导入pkg.C时,pkg未加载,因为它已加载,而是将名称pkg导入A.py 引用script.py中导入的同一模块对象时的命名空间。由于属性B已添加到该对象(script.pypkg.B.test成功,即使它已在A.py中执行。