我有一个名为tokenize.py
的本地模块,它掩盖了同名的标准库模块。我只是在尝试导入外部模块(sklearn.linear_model)时发现了这一点,而外部模块又是import tokenize
并期望获得标准库模块,而是获取我的本地模块。
这与How to access a standard-library module in Python when there is a local module with the same name?有关,但设置不同,因为应用上述解决方案需要修改外部模块。
一个选项是重命名本地tokenize.py
,但我不愿意这样做,因为“tokenize”最能表达模块的角色。
为了说明问题,这里是模块结构的草图:
\my_module \__init__.py \tokenize.py \use_tokenize.py
在use_tokenize.py中,有以下导入:
import sklearn.linear_model
调用python my_module/use_tokenize.py
时会导致以下错误:
Traceback (most recent call last):
File "use_tokenize.py", line 1, in <module>
import sklearn.linear_model
<...>
File "<EDITED>/lib/python2.7/site-packages/sklearn/externals/joblib/format_stack.py", line 35, in <module>
generate_tokens = tokenize.tokenize
AttributeError: 'module' object has no attribute 'tokenize'
导入外部模块时有没有办法抑制本地模块?
编辑:添加了python2.7作为标记,因为解决方案因Python版本而异。
答案 0 :(得分:3)
问题不在于模块名称,而是在运行模块,就像它是脚本一样。当Python运行脚本时,它会将脚本的包含目录添加为sys.path
中的第一个元素,因此从任何地方进行的所有模块查找都将首先搜索该目录。
要避免这种情况,请让Python将其作为模块执行:
python -m my_module.use_tokenize
或者,当然,您可以将可执行脚本保留在模块层次结构之外。
答案 1 :(得分:0)
解释器搜索模块的路径列在sys.path
中。为防止第三方模块在导入时看到本地模块,我们从路径中删除.
。这可以通过以下方式实现:
import sys
sys.path = sys.path[1:]
import sklearn.linear_model #using the original example.
但是,如果已导入本地tokenize
,则无法执行此操作,并且即使我们将旧的tokenize
还原为“{1}},也会阻止导入本地sys.path
”如下:
import sys
old_path = sys.path
sys.path = sys.path[1:]
import sklearn.linear_model #using the original example.
sys.path = old_path
这是因为Python解释器维护导入模块的内部映射,以便从此映射中满足以后对同一模块的请求。这个映射对于解释器是全局的,因此import tokenize
从运行它的任何代码返回相同的模块 - 这正是我们试图改变的行为。为此,我们必须改变这种映射。最简单的方法是从sys.modules
中删除相关条目。
import sys
old_path = sys.path
sys.path = sys.path[1:]
import sklearn.linear_model #using the original example.
sys.path = old_path
del sys.modules['tokenize'] #get of the mapping to the standard library tokenize
import tokenize #cause our local tokenize to be imported