给定以下目录结构:
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中的默认行为.新行为(假设绝对和显式相对导入) )很大程度上是为了解决你提出的问题(遮蔽内置模块)而实现的,尽管它还允许使用多级相对导入语法进行更大的控制(即…对于父模块,…对于更高级别的级别,以及等等.)