在开发Python包时,使用-m
选项将包内的模块作为脚本进行快速测试非常方便。例如,对于其中包含模块somepackage
的{{1}},请调用
somemodule.py
来自python -m somepackage.somemodule
所在目录的将运行somepackage
,就好像子模块是somemodule.py
一样。如果程序包使用here所述的显式相对导入,则使用此调用语法尤为重要。
同样,使用__main__
选项调试脚本也很方便,如
-m
有没有办法同时做两件事?也就是说,我可以将模块称为脚本并同时启动调试器吗?我意识到我可以进入代码本身并将python -m pdb somescript.py
插入我想要破解的地方,但我试图避免这种情况。
答案 0 :(得分:8)
经过一段时间的实验,结果证明这种方法确实有效:
python -c "import runpy; import pdb; pdb.runcall(runpy.run_module, 'somepackage.somemodule', run_name='__main__')"
出于某种原因,使用pdb.runcall
而非pdb.run
非常重要。
答案 1 :(得分:6)
有efforts underway在Python本身解决这个问题。看起来像Python 3.7,你可以这样做:
python -m pdb -m somepackage.somemodule
我已经为旧的Python版本(2.7 +)提供了a backport:
pip install backports.pdb
python -m backports.pdb -m somepackage.somemodule
答案 2 :(得分:0)
这是另一个也适用于命令行参数的选项。
将脚本的逻辑包装在main
函数中通常是个好主意。然后,您可以main
接受可选的参数列表以覆盖sys.argv
。这是一个名为argdemo.py
的示例:
def main(cmd_line_args=None):
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("number", help="a number", type=int)
# allow cmd_line_args to override sys.argv
if cmd_line_args is None:
args = parser.parse_args()
else:
args = parser.parse_args(cmd_line_args)
print("The number is {}".format(args.number))
if __name__ == '__main__':
main()
此模块可以照常运行:
$ python -m argdemo 2
> The number is 2
或者可以通过pdb
直接调用main()
来运行它:
$ python -c "import pdb; import argdemo; pdb.runcall(argdemo.main, ['2'])"
(Pdb) continue
> The number is 2
(请注意,cmd_line_args
必须是一个字符串列表,就像argv
一样。
作为额外的好处,当您的模块具有可导入的main
功能时,您可以以相同的方式为其编写单元测试=)
答案 3 :(得分:0)
在@jed的回答基础上,我构建了这个模块:
import pdb
import runpy
import sys
def main():
module = sys.argv[1]
sys.argv[1:] = sys.argv[2:]
pdb.runcall(runpy.run_module, module, run_name='__main__')
__name__ == '__main__' and main()
将该模块作为mpdb.py
放在Python Path中的任何位置(当前目录有效),然后您可以调用:
python -m mpdb somepackage.somemodule even with args
答案 4 :(得分:0)
这对我有用(使用-m选项将python模块调试为脚本)
我创建了一个草稿
import runpy
if __name__ == '__main__':
runpy.run_module('somepackage.somemodule', run_name="__main__", alter_sys=True)