如何获取Python解释器的完整argv命令行选项?

3

正如我们从文档中所知道的:

-c 如果给出此选项,则 sys.argv 的第一个元素将是“-c”,并且当前目录将添加到 sys.path 的开头(允许在该目录中导入顶级模块)。

我该如何获取完整的解释器命令行选项? 我需要它来解决这个问题:

https://github.com/mitsuhiko/werkzeug/blob/f50bdc04cf1c8d71d12d13a0c8ef2878477f4d24/werkzeug/_reloader.py#L141

如果我启动 werkzeug 开发服务器,那么它将在 fork 上丢失 -c cmd 选项。 我想修补 werkzeug,但找不到如何获取真实选项。

如果您想知道为什么我需要这个 - 我想在 manage.py 之前预执行一些代码,这些代码希望解析 sys.argv。 我还认为 werkzeug 方法不正确,因为它在某些情况下无法正常工作。

1个回答

2

如果我启动werkzeug开发服务器,那么它将在fork时失去-c cmd选项。

首先,这个进程不仅仅是被fork了。而是调用了一个新的Python解释器。

你所说的“它将失去-c cmd”是什么意思?是指cmd字符串在argv中消失了吗?也就是:

$ python -c "import sys; print(sys.argv)"
['-c']

实际上,从sys.argv中无法访问cmd字符串。相关文档在此处:

如果使用-c命令行选项运行命令,则argv[0]设置为字符串'-c'

文档没有对实际命令字符串进行评论。虽然该命令字符串显然作为Python解释器可执行文件的参数“发送”,但CPython实现似乎不会在sys.argv中公开此信息。我猜想,除非更改sysmodule.c的源代码,否则无法重构此信息。因此,如果您认为您依赖提取cmd,那么您应该找到另一种注入此信息的方法。 编辑: 实际命令字符串在函数Py_Main()中在Modules/main.c 中被消耗。
wcscpy(command, _PyOS_optarg);

command是稍后在main.c中执行的命令。

命令行参数通过PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);进行处理,它又调用了sysmodule.c中的makeargvobject()函数。后者在类似于for (i = 0; i < argc; i++) {}的循环中将二进制参数数据转换为Python Unicode对象(至少在Python 3中是这样)。因此,在该循环中,必须(有意地)将argc减去1才能忽略该命令。

也就是说,取消命令参数的魔法在于设置_PyOS_optind,使得随后对PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);的调用建议比实际上小一个参数计数。

我没有完全跟进,但我想这些代码中的递减可能是有责任的:

if (command != NULL) {
    /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
    _PyOS_optind--;
    argv[_PyOS_optind] = L"-c";
}

编辑2:

通过对当前Python 3的以下补丁进行验证,确认了_PyOS_optind的关键作用:

diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -679,9 +679,11 @@
     }

     if (command != NULL) {
         /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
         _PyOS_optind--;
-        argv[_PyOS_optind] = L"-c";
+        _PyOS_optind = 0;
+        //argv[_PyOS_optind] = L"-c";
     }

     if (module != NULL) {

测试:

 $ ./python -c "import sys; print(sys.argv)"
['./python', '-c', 'import sys; print(sys.argv)']

1
谢谢!我没有找到 cmd 真正的条带位置。在这个档案中,我已经发现了 Py_GetArgcArgv!然后我尝试了一些奇怪的东西,结果很奇怪:>>> python -c 'import ctypes; argv = ctypes.POINTER(ctypes.c_char_p)(); argc = ctypes.c_int(); ctypes.pythonapi.Py_GetArgcArgv(ctypes.byref(argc), ctypes.byref(argv)); print([argv[i] for i in xrange(0, argc.value)])' ['python', '-c', '-c'] - Mihail Krivushin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接