【问题标题】:Importing module from sub-package in current directory when it clashes with site-packages与站点包冲突时从当前目录中的子包导入模块
【发布时间】:2015-07-11 04:37:28
【问题描述】:

我的site-packages 目录中有a.b.c.d 包中的模块e

/usr/lib/python2.7/site-packages/a/b/c/__init__.py
/usr/lib/python2.7/site-packages/a/b/c/d/__init__.py
/usr/lib/python2.7/site-packages/a/b/c/d/e.py

__init__.py 在这两种情况下都是空的。我在当前目录中镜像了这个目录结构:

a/b/c/__init__.py
a/b/c/d/__init__.py
a/b/c/d/e.py

我运行 python 2.7 并输入:

from a.b.c.d.e import foo

导入的是site-packages 版本,而不是本地版本。 sys.path[0] 是空字符串。我希望并在文档/Google 中发现当前目录因此优先。我还尝试在当前目录的a/ba 目录以及当前目录本身中添加__init__.py

如果我将第一个目录重命名为 z,则本地导入有效(为 zb 设置了额外的 __init__.pys,并适当更改了导入语句)。

site-packages 包含a.b.c-VERSION-nspkg.pth

import sys,types,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('a',)); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('a',types.ModuleType('a')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p) import sys,types,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('a', 'b')); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('a.b',types.ModuleType('a.b')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p); m and setattr(sys.modules['a'], 'b', m)

为什么我不能像这样覆盖模块?可能是因为sys.modules 已经包含该模块?我可以强制以某种方式覆盖它吗?

【问题讨论】:

  • 这是什么 Python 版本?在 2.x 和早期 3.x 中,a 不是一个包,如果它没有 __init__.py,你的都没有(但站点包可能明确添加了一个 .pth 文件)。在后来的 3.x 中,a 是一个命名空间包,会将两者合并在一起(但 a.b.c 不是,所以必须取其一)。
  • 我已经添加了更多的 2.7 参考和详细信息,我尝试添加更多 __init__.pys。
  • 来自问题末尾的评论,“可能是因为 sys.modules 已经包含该模块吗?”:如果您已经在当前会话中导入了它,然后尝试更改内容(无论是在文件系统上还是在 sys.path 中),那么是的,那将失败。但是在新的解释器会话中,这些东西没有理由出现在 sys.modules 中。
  • 当我启动解释器时,sys.modules 不是空的 - 我相信它包含来自site-packages 的所有内容。这同样适用于不同的操作系统/Python 次要版本。
  • 它不应该是empty,但如果它实际上包含来自site-packages的所有内容,那就大错特错了。

标签: python python-2.7 python-import python-module


【解决方案1】:

从你的 cmets 来看,问题是:

  • 你的a 不是包,因为在 Python 3.3 之前,没有__init__.py 文件的目录永远不是包。这意味着您的 a.b.c 也不是一个包。

  • 这意味着site-packages 中的a 也不应该是一个包,但是……

  • site 中有一个.pth 文件,它强制将a.b.csite-packages 副本无论如何都作为一个包。

在这一点上,我不确定你想做什么来覆盖它。听起来你想变得非常hacky并从sys.modules中删除现有的包,然后强行插入你自己的包,或者类似的东西。当然你可以这样做,如果你自己猜不出来,我可以给你看代码。 (或者您可能想搜索 numpy_override,它具有类似的技巧,用于预装过时或系统回购安装的 numpy 的系统。)但我认为你'最好首先重新考虑您的问题。例如,为什么不直接构建一个包含您的包的virtualenv,而不是其site-packages 中的系统site-packages 包?

【讨论】:

  • 我认为这不是真的。当我编辑问题时,将__init__.py 添加到aa/b 时会出现同样的问题。我也可以重命名顶层并成功导入,证明是包。
猜你喜欢
  • 2017-02-07
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
  • 2015-12-22
相关资源
最近更新 更多