python – import语句是如何找到该模块的?

给定以下目录结构:

here/
├── app
│   ├── __init__.py
│   ├── json.py
│   └── example.py
└── my_script.py

__init__.py和json.py是空文件.

my_script.py的内容:

from app import example

example.py的内容

import importlib, imp, sys, os

# ensures '' is not in sys.path
sys.path = [p for p in sys.path if p]

# ensures PYTHONPATH, if any, is not over-reaching
os.environ.pop('PYTHONPATH', None)

# ensures we do not see json.py in the cwd
assert not os.path.isfile('json.py')

print '1: ', imp.find_module('json')
print '2: ', __import__('json')
print '3: ', importlib.import_module('json')

import json
json.loads

现在,从这里的目录,执行:

python ./my_script.py

您将看到方法1,2,3都找到了json模块的核心库版本.

但是,实际的import语句仍设法以某种方式获取空的json.py文件(AttributeError:’module’对象没有属性’loads’).

我的理解是这里的json的包版本应该只能通过命名空间访问,即从app import json访问,但是命名空间似乎在这里不起作用.

在python3上,我无法重现这个问题.我还注意到,如果我们将__future__ import absolute_import放入example.py文件中,问题就会消失.

import语句如何找到本地文件,为什么它会影响核心库版本?

编辑:在另一个小注释上,当我们到达行导入json时,已经有一个json模块从上面的行加载到sys.modules中.那么为什么python会再次尝试导入模块,难道它不应该只使用模块缓存中已有的模块吗?

最佳答案 你或多或少得到了答案.默认情况下,Python 2.x将首先执行包相对导入,其中包括“遮蔽”基础包的可能性.

请参阅python 2文档中的Intra-package References部分.

指定显式相对导入以及__future__ import absolute_import的能力实际上是在Python 2.5中引入的,这在PEP 328中进一步解释.这种行为成为Python 3中的默认行为.新行为(假设绝对和显式相对导入) )很大程度上是为了解决你提出的问题(遮蔽内置模块)而实现的,尽管它还允许使用多级相对导入语法进行更大的控制(即…对于父模块,…对于更高级别的级别,以及等等.)

点赞