Python -m命令中的sys.argv行为

9

关于Python 3.5.2中__init__.py行为的问题。我注意到"sys.argv"和"import __main__"的调用时间不同,它们的行为也不同。例如:

$ tree 
└── subdir
    ├── __init__.py : "import sys; print(sys.argv)"
    ├── __main__.py : "import sys; print(sys.argv)"

$ python -m subdir
['-m']
['/path/to/code/subdir/__main__.py']

在这里,我感到措手不及,因为我期望sys.argv在整个进程的生命周期中保持不变。我有一种直觉,为什么会发生这种情况,但我想知道是否有任何方法可以在导入__init__.py模块时了解真实的sys.argv。

供参考,看起来argv在Lib/runpy.py@_run_module_as_main中被更改。


https://docs.python.org/3/using/cmdline.html#cmdoption-m 正好描述了这个。 - Josh Lee
1
@JoshLee 很好的提醒,“sys.argv 的第一个元素将是模块文件的完整路径”展示了 sys.argv 的实现相关性变化,但我仍然想知道在 init.py 文件导入时,如何简洁地适应 sys.argv 可能还没有最终确定的情况。 - Buck
@Buck 我认为最好的解决办法是在__init__.py中不关心 sys.argv。您在__init__中所做的,在__main__中也可以做到,对吧? - Piotr Dobrogost
1
@PiotrDobrogost我需要sys.argv的原因只是为了知道哪个文件被作为__main__运行,在实践中,我有一些会在导入时初始化其记录器的模块,例如logger = getLogger(__name__),并且希望这些记录器能够附加关于主进程的额外信息,但我发现没有好的方法让它们在导入时始终具备该信息。 - Buck
1个回答

5

简短版:在运行之前找不到__main__的方法。

详细版:

  • -m标志会导致sys.argv[0]被操作
  • 问题在于sys.argv被操作的时间
    • main.c@Py_main进行了一些标志解析并弹出要调用的模块名称
    • main.c@RunModule是runpy.py@_run_module_as_main的包装器
    • _run_module_as_main设置了sys.argv[0],但是直到调用runpy.py@_get_main_module_details之后才这样做
      • _get_module_details中的副作用实际上导入了包及其祖先,执行__init__.py脚本,因此_run_module_as_main无法设置sys.argv

我认为可以重构代码,使得在_get_module_details导入包和祖先之前设置sys.argv成为可能(我认为这是模块规范所实现的),但需要等待runpy架构的增强,可能是通过这个来实现的,该项目最近正在进行中。


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