当本地模块屏蔽外部模块导入的标准库模块时,如何导入外部模块?

时间:2013-02-28 00:27:17

标签: python python-2.7

我有一个名为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版本而异。

2 个答案:

答案 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