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

时间:2016-02-25 21:06:55

标签: python python-2.7 python-import

给出以下目录结构:

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

__init__.pyjson.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

现在,从here目录执行:

python ./my_script.py

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

但是,实际的import语句仍设法以某种方式获取空json.py文件(AttributeError: 'module' object has no attribute 'loads')。

我的理解是这里json的包版本只能由命名空间访问,即from app import json,但命名空间似乎不适用于此处。

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

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

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

1 个答案:

答案 0 :(得分:2)

你或多或少得到了答案。默认情况下,Python 2.x将首先执行包相对导入,其中包括" shadowing"基础包。

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

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