Python模块导入是否取决于代码的运行方式?

Do Python module imports depend on how the code is run?

本问题已经有最佳答案,请猛点这里访问。

我认为任何语言都不会像python那样在导入其他源文件的过程中引起如此简单的问题。所以问题是:我的模块导入是否需要依赖于代码的运行方式?

我有以下目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
./__init__.py
./config.py
./kmer
./kmer/__init__.py
./kmer/__main__.py
./kmer/__pycache__
./kmer/__pycache__/__init__.cpython-36.pyc
./kmer/__pycache__/__main__.cpython-36.pyc
./kmer/__pycache__/bed.cpython-36.pyc
./kmer/__pycache__/config.cpython-36.pyc
./kmer/__pycache__/reference.cpython-36.pyc
./kmer/__pycache__/sets.cpython-36.pyc
./kmer/bed.py
./kmer/config.py
./kmer/reference.py
./kmer/sets.py

我希望从kmer包内的另一个模块导入khmer内的模块。简单吗?

所以我在bed.py的处加上:

1
2
3
import reference
import config
import sets

现在,如果我从kmer目录运行python bed.py,事情就可以正常工作了。如果我返回一个目录并打电话给python kmer/bed.py,事情也会好起来的。似乎python在搜索与给定文件相关的导入模块。

再次从kmer目录中以python -m bed的形式运行它可以正常工作,但是返回一个目录并运行python -m kmer.bed会导致模块错误。在这里,python似乎在解释器的当前目录中查找模块,该目录可能位于文件系统的任何位置,因此相对于它的导入不应该工作。

这基本上意味着导入应该取决于代码的运行方式,这毫无意义。我希望能得到一些关于这应该如何工作的解释。

我已经看了很多资源,包括这个问题的答案,虽然非常详细(实际上我发现的最好的描述之一)并不能解决我的问题,也不能提供适当的例子。

更新:我认为这个问题更关注相对导入的不同方面,更准确地说,运行代码的不同方法如何影响导入,而不是它被标记为的副本。所以我首先提到了另一个问题。因此,我认为这不应该是重复的。


编写包时,必须始终将其视为包。首先,这意味着在包中使用相对导入:在bed.py中写入from . import reference

它还意味着如何访问它的答案总是一样的:将包含kmer的目录放到sys.path上(通常通过PYTHONPATH访问)。即使将包中的某个模块作为脚本运行,也是如此,因此它必须是python -m kmer.bed

不幸的是,在包内运行一个模块作为脚本是一个坏主意:模块的文件仍然有资格以其正确的名称再次导入(而不是第一次使用的__main__)。唯一可靠的解决方案是编写一个__main__.py并以脚本的形式运行包,避免重载公共模块名。

最后,不要太关注python将脚本目录放在sys.path上的"特性"。除了不关心名称冲突的玩具问题之外,这是没用的,因为任何目录在sys.path上有用的脚本都必须是一个模块(除了让其名称不是标识符这样的技巧)。此外,如果您希望您的库可以用于安装在其他地方的脚本,那么它无论如何都需要以其他方式安装sys.path