给出以下目录结构:
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
现在,从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会再次尝试导入模块,不应该只使用模块缓存中已有的模块吗?
答案 0 :(得分:2)
你或多或少得到了答案。默认情况下,Python 2.x将首先执行包相对导入,其中包括" shadowing"基础包。
请参阅python 2文档中的Intra-package References部分。
指定显式相对导入的能力以及from __future__ import absolute_import
实际上是在Python 2.5中引入的,这在PEP 328中进一步解释。这种行为成为Python 3中的默认行为。新行为(假定绝对和显式相对导入)在很大程度上是为了解决您提出的问题(遮蔽内置模块)而实现的,尽管它还允许使用多级相对导入语法进行更好的控制(即..
用于父模块,...
用于更高级别,等等。)