为什么Python的`from`形式的import语句绑定模块名称?

Cea*_*sta 24 python import

我有一个具有以下结构的Python项目:

testapp/
??? __init__.py
??? api
?   ??? __init__.py
?   ??? utils.py
??? utils.py
Run Code Online (Sandbox Code Playgroud)

所有模块都是空的,除了testapp/api/__init__.py它有以下代码:

from testapp import utils

print "a", utils

from testapp.api.utils import x

print "b", utils
Run Code Online (Sandbox Code Playgroud)

testapp/api/utils.py其限定x:

x = 1
Run Code Online (Sandbox Code Playgroud)

现在从我导入的根目录testapp.api:

$ export PYTHONPATH=$PYTHONPATH:.
$ python -c "import testapp.api"
a <module 'testapp.utils' from 'testapp/utils.pyc'>
b <module 'testapp.api.utils' from 'testapp/api/utils.pyc'>
Run Code Online (Sandbox Code Playgroud)

导入的结果让我感到惊讶,因为它表明第二个import语句已被覆盖utils.然而,文档声明from语句不会绑定模块名称:

from表单不绑定模块名称:它遍历标识符列表,在步骤(1)中找到的模块中查找每个标识符,并将本地名称空间中的名称绑定到找到的对象.

事实上,当我在终端中使用from ... import ...语句时,不会引入任何模块名称:

>>> from os.path import abspath
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
Run Code Online (Sandbox Code Playgroud)

我怀疑这与Python有关,在第二次导入语句时,尝试导入testapp.api.utils引用testapp.utils和失败,但我不确定.

这里发生了什么?

use*_*ica 14

导入系统文档:

当使用任何机制(例如importlibAPI,importimport-from语句或内置__import__())加载子模块时,绑定将放置在父模块的命名空间中,并放置到子模块对象中.例如,如果包spam具有子模块foo,则在导入之后spam.foo,spam将具有foo绑定到子模块的属性.假设您有以下目录结构:

spam/
    __init__.py
    foo.py
    bar.py
Run Code Online (Sandbox Code Playgroud)

spam/__init__.py在其中包含以下内容:

from .foo import Foo
from .bar import Bar
Run Code Online (Sandbox Code Playgroud)

然后执行以下把将名称绑定到foobar所述在spam模块:

>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.bar
<module 'spam.bar' from '/tmp/imports/spam/bar.py'>
Run Code Online (Sandbox Code Playgroud)

鉴于Python熟悉的名称绑定规则,这似乎令人惊讶,但它实际上是导入系统的基本功能.不变控股是,如果你有sys.modules['spam']sys.modules['spam.foo'](可能也会上述进口后),后者必须表现为foo前者的属性.

如果这样做from testapp.api.utils import x,import语句将不会加载utils到本地名称空间.但是,导入机制加载utilstestapp.api命名空间中,以使进一步的导入正常工作.在您的情况下,它恰好testapp.api也是本地命名空间,因此您会感到惊讶.

  • @CeasarBautista:模块名称未绑定在*local*命名空间中,但它*绑定在包的命名空间中.只是在这种情况下,那些是相同的命名空间. (2认同)