将工作目录添加到 sys.path 的方式在使用 `-c` 或 `-m` 之间有所不同

Ana*_*and 5 python python-import pythonpath language-lawyer

如果您从命令行(带有-c标志)或通过指定模块路径(带有-m标志)作为单个命令启动 Python 进程,则工作目录将附加到sys.path. 从文档(强调我的):

  • -c <命令>

    [...]

    如果给出这个选项,第一个元素sys.argvwill"-c"当前目录将被添加到开头sys.path(允许该目录中的模块作为顶级模块导入)。

    [...]

  • -m <模块名称>

    [...]

    如果给出此选项,则 的第一个元素sys.argv将是模块文件的完整路径(在定位模块文件时,第一个元素将设置为"-m")。与 -c选项一样, 当前目录将被添加到 sys.path.

    [...]

但似乎每个选项的完成方式都不同:

$ python -c "import sys; print sys.path"
['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/plammens/.local/lib/python3.8/site-packages', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']

$ python -m script  # script.py does the same as the command above
['/mnt/c/Users/Paolo/Desktop/Code Sandbox/Python/clean', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/plammens/.local/lib/python3.8/site-packages', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']
Run Code Online (Sandbox Code Playgroud)

请注意第一个选项如何使用空字符串来表示当前工作目录,而第二个选项则明确地将路径添加到我运行命令的目录中。

根据导入系统上的文档,在执行期间始终动态解释空字符串以表示当前工作目录:

当前工作目录(由空字符串表示)的处理方式与 上的其他条目略有不同sys.path。首先,如果发现当前工作目录不存在,则不存储任何值sys.path_importer_cache。其次,对于每个模块 lookup 都会重新查找当前工作目录的值。第三,用于sys.path_importer_cache和返回 的路径importlib.machinery.PathFinder.find_spec()将是实际的当前工作目录,而不是空字符串。

所以这意味着-c版本将始终使用 Python 进程的当前工作目录,而不是它最初启动的目录。

事实上,我们可以举一个例子来说明这一点。考虑以下文件树,

.
??? script.py
??? secret-folder
    ??? findme.py
Run Code Online (Sandbox Code Playgroud)

findme.py只包含一个声明print("you found me!")。如果我们运行以下

import os
os.chdir('secret-folder')
import findme
Run Code Online (Sandbox Code Playgroud)

作为命令 ( -c) 和脚本 (in script.py),我们得到:

$ python -c "import os; os.chdir('secret-folder'); import findme"
you found me!

$ python -m script
Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/.../script.py", line 5, in <module>
    import findme
ModuleNotFoundError: No module named 'findme'
Run Code Online (Sandbox Code Playgroud)

这是因为-m正在使用“硬编码”工作目录,同时-c使用“动态解释”当前目录。

通过它在文档中的措辞-c和方式-m,人们会认为这两者的行为应该相同。

这是故意的吗?如果是这样,则没有记录。


更新-在 BPO 上打开了一个问题