PYTHONPATH 与 sys.path(重载)

2 投票
2 回答
2255 浏览
提问于 2025-04-18 05:58

我想重新讨论一下在PYTHONPATH和sys.path中的问题。基本上,这个问题是关于如何开发一个像这样的包:

Project
    setup.py
    package
        __init__.py
        lib.py
        script.py

假设script.py中有from package.lib import foo这行代码,当你在以下情况下调用它时是可以正常工作的:

python -m package.script

setup.py所在的目录运行,但在以下情况下调用时就不行了(在Windows上,使用CPython 2.7):

.\package\script.py

ImportError: No module named package

在第一种情况下,当你打印sys.path时,第一项是'',而在第二种情况下,第一项是script.py所在的绝对路径。当然,在这种情况下,它对package一无所知,所以导入失败了。当你在资源管理器中双击文件时也是这样。

原来的StackOverflow问题建议通过setup.py develop来安装包。然而,在当前的setuptools 3.5中(我知道并且对distutils和setuptools的重命名感到困惑),这个选项甚至没有被记录(我有setuptools 3.4.x,但没有尝试过)。

有没有人能告诉我,在Windows上(针对CPython 2.7,同时也考虑到Python 3),双击文件并让它正常工作的推荐步骤是什么?相对导入?

2 个回答

1

你可能需要仔细阅读一下模块搜索路径的相关文档。注意,搜索路径会包括“包含输入脚本的目录(或者当前目录)”。当你用 python -m package.script 这个命令时,由于没有输入脚本,当前目录就会被使用(script.py 被当作一个模块来用)。而当你运行 .\package\script.py 时,它会把 .\package 加入到搜索路径中。

解决你这个问题的办法是把所有可执行的脚本放在你库的基础目录下。也就是说,把 script.py 移动到上一级目录。

2

现在更好的做法是使用 pip install 命令,并加上 -e 选项。

pip install -e .

这个方法需要一个包含 setup.py 文件的目录。这里的“.”表示当前这个目录。这种方式和 setuptools 的开发模式是一样的。

我认为,使用开发模式会在你的 site-packages 文件夹里创建一个指向库文件夹的链接。你可以查看这个链接了解更多信息:http://pythonhosted.org/setuptools/setuptools.html#develop-deploy-the-project-source-in-development-mode

python setup.py develop

我想这就是你得到绝对路径的原因。可能会出现开发链接和安装之间的冲突,或者文件可能被移动了。

如果你想通过双击来运行程序,可以检查一下 sys.argv。如果 sys.argv[1] 没有值,就加上 build、install 或 develop。

另外,我一直听说,最好先导入模块,然后再调用模块里的函数。比如用 from package import lib,然后用 lib.foo() 这样你就能清楚知道这个方法是从哪里来的。我认为这两种导入方式的效果是一样的;这样可能会让你的导入更整洁。Python 的路径和打包确实有点麻烦。

from package import lib
lib.foo()

撰写回答