6

我有一个正在编写的 python 包,但由于名称冲突,我遇到了一个问题,即导入标准库而不是我的文件。

例如,如下所示的文件结构:

package/__init__.py

# No data in this file

包/模块.py

#!/usr/bin/env python
print 'Loading module.py'
import signal

包/信号.py

#!/usr/bin/env python
print 'Loading signal.py'

当我运行它时,我得到以下结果:

$ ./module.py
Loading module.py

我想得到:

$ ./module.py
Loading module.py
Loading signal.py

实际问题:

因此,当我运行module.py时,它import signal会转到 stdlib 版本。我怎样才能强制module.py导入 signal.py 呢?

如标签中所述,这需要能够在 python-2.4.3 上运行。虽然这是一个旧版本,但它包含在 RHEL 5 中。


一些附加信息

只是为了获得更多信息,我明确地有以下设置:

[10:30pm][~/test] tree .
.
|-- package
|   |-- __init__.py
|   |-- module.py
|   `-- signal.py
`-- script

[10:30pm][~/test] cat script
#!/usr/bin/env python
from package import signal

[10:30pm][~/test] cat package/__init__.py

[10:30pm][~/test] cat package/module.py 
#!/usr/bin/env python
print "Loading module.py"
import signal

[10:30pm][~/test] cat package/signal.py 
#!/usr/bin/env python
print "Loading signal.py"

[10:30pm][~/test] python ./script
Loading signal.py

[10:32pm][~/test] python ./package/module.py 
Loading module.py

[10:32pm][~/test] python -m package.module
python: module package.module not found

请注意,当我运行./package/module.py时,./package/ signal.py中的打印语句没有被触发。这意味着加载的信号是来自标准库的信号。

4

3 回答 3

6

这种情况下的问题是内置signal模块是作为解释器启动过程的一部分导入的。因此,当您的代码module.py运行时,在 name 下已经有一个条目,其值是内置模块。由于是语句首先出现的位置,因此它将返回该内置模块并停在那里。它甚至不费心去寻找你自己的 custom 。sys.modulessignalsys.modulesimportsignal.py

我可以想到三个解决方案:

  1. 重命名您的模块。这是最简单的解决方案。您不必担心您的模块名称与已安装的软件包(eggs)发生冲突,因为通常import语句将按照 指定的顺序搜索目录sys.path,并且当您运行解释器时,当前工作目录位于该列表的第一位。signal是一种特殊情况,因为它会在您的代码运行之前自动导入,但是只有有限数量的模块是正确的,而这些是您唯一需要避免名称冲突的模块。
  2. 您可以del sys.modules['signal']用您自己的自定义signal模块替换条目。除非您的模块确实是为了替代内置的signal. 如果你这样做了,那么从那时起运行import signal的任何代码都会得到你的版本,而不是内置版本,这可能会对任何需要signal模块运行的内部代码造成严重破坏。
  3. 您可以使用该imp模块来访问import函数的内部,或者至少是等效代码,这将允许您绕过对sys.modules.

    如果您确实需要这样做,可以使用以下代码示例:

    import imp, sys
    
    f, path, desc = imp.find_module('signal', sys.path)
    if f:
        f.close()
        signal = imp.new_module('signal')
        execfile(path, signal.__dict__)
    else:
        raise ImportError('signal.py not found')
    # signal is your module
    

    这段代码大致相当于,import signal只是它不将找到的模块插入到sys.modules中,并且在搜索路径之前不查找内置模块。

于 2011-12-19T06:51:01.863 回答
0

从项目目录(目录的父级package):

python -mpackage.state # Python 2.6+
python2.4 -c'from package.state import test; test()'
  • 总是在你的模块中使用绝对导入,import package.signal而不是import signal除非你知道你在做什么
  • 确保它package的父目录在sys.path. unittest2, nose,pytest测试运行者可能会为你做这件事
  • 避免与 stdlib 模块冲突的模块名称。许多测试运行器,代码分析器被破坏并添加带有正在处理的模块的目录sys.path
  • python package/stat.py添加packagesys.path(参见http://bugs.python.org/issue13475)。在这种情况下你不希望这样
于 2011-12-19T08:11:44.170 回答
-1

文件层次结构

.
|-- package
|   |-- __init__.py
|   |-- module.py
|   `-- signal.py
`-- script
`-- __init__.py

脚本.py

#!/usr/bin/env python
from package import module

包/模块.py

#!/usr/bin/env python
print 'Loading module.py'
from package import signal

包/信号.py

#!/usr/bin/env python
print 'Loading signal.py'

输出:

$ ./script 
Loading module.py
Loading signal.py

编辑

刚刚在 python 2.4.3 上通过修改 module.py 测试了这个

于 2011-12-19T04:33:11.023 回答