【问题标题】:How do I import an external module when a local module masks a standard library module imported by the external module?当本地模块屏蔽外部模块导入的标准库模块时,如何导入外部模块?
【发布时间】:2013-02-28 00:27:17
【问题描述】:

我有一个名为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”最能表达模块的作用。

为了说明问题,这里是模块结构的草图:

\我的模块 \__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 作为标签,因为 cmets 解决方案因 Python 版本而异

【问题讨论】:

  • 您使用的是哪个版本的 Python?规则和解决方法不同。
  • 但实际上,您应该重命名本地 tokenize.py。自动修复所有数百个脚本和模块中的所有import tokenizetokenize. 的脚本应该需要几分钟的编写和几秒钟的运行......
  • 如果你创建一个与标准库模块同名的模块,没有人可以在不屏蔽标准库模块的情况下安装你的库。解决方案是不要给你的模块起这个名字。 (如果它是包的一部分,您仍然可以拥有 tokenize.py,因为在这种情况下,简单的 import tokenize 将看不到它。)
  • 我很欣赏重命名模块是一种解决方案,但实际上并不能回答问题。鉴于标准库相当大,命名空间冲突并不令人惊讶,而相对导入机制解决了这个问题。但是,如何处理不使用相对导入的第三方代码?
  • 我也会把我的帽子扔进“重命名标记化”堆。这可能不会导致巨大的错误,但与标准库的命名空间冲突很容易避免。

标签: python python-2.7


【解决方案1】:

问题不在于模块名称,而在于您正在运行一个模块,就像它是一个脚本。当 Python 运行脚本时,它会将脚本的包含目录添加为 sys.path 中的第一个元素,因此任何地方的所有模块查找都将首先搜索该目录。

为避免这种情况,请让 Python 将其作为模块执行:

python -m my_module.use_tokenize

或者,当然,您可以将可执行脚本保留在模块层次结构之外。

【讨论】:

    【解决方案2】:

    解释器在其中搜索模块的路径在sys.path 中列出。为了防止第三方模块在导入时看到本地模块,我们从路径中删除了.。这可以通过以下方式实现:

    import sys
    sys.path = sys.path[1:]
    import sklearn.linear_model #using the original example.
    

    但是,如果本地的tokenize已经被导入,这将不起作用,并且它也会阻止本地的tokenize被导入,即使我们恢复旧的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    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-27
      • 2010-11-25
      相关资源
      最近更新 更多