【问题标题】:In Python, how to invoke subroutine inside [if __name__ == '__main__'] of another py file?在 Python 中,如何在另一个 py 文件的 [if __name__ == '__main__'] 中调用子程序?
【发布时间】:2023-04-01 11:20:01
【问题描述】:

假设我在 python 控制台中并且想在同一个进程中启动另一个 python 程序。 python程序如下所示:

import sys

if __name__ == '__main__':
      args = sys.argv
      for key in args:
          print(key)

我不能修改它。

这样做的正确方法是什么?我可以用不同的参数列表(如 C++ 或 Java)将其称为“主函数”吗?

我不反对被认为是黑客攻击的方法。 Python 是一种高度可扩展的解释性语言,我会做任何必要的事情来绕过这个限制

【问题讨论】:

  • 澄清一下,您根本不允许触摸python文件吗?对我来说听起来像是一些 CTF 问题。
  • 将其作为脚本运行,因为它打算运行。
  • @pkqxdd,不,我不能,具体来说,原始不可触及的文件是mavproxy.py。这绝对不是 CTF 问题

标签: python main python-module


【解决方案1】:

你不能“调用它的主函数”,因为它没有。

事实上,处理这个问题的常用方法是将所有这些代码移动到一个函数中,然后让 __main__ 保护代码调用它:

def main(args):
    for key in args:
        print(key)

if __name__ == '__main__':
    main(sys.argv)

然后你可以调用它的主函数,传递你想要的任何参数。

但是如果你不能修复这个文件,那是行不通的。


那么,可以做什么呢?这完全取决于您需要在多大程度上遵循通常的python another.py 语义。


快速而肮脏的方法是执行blhsing's answer 建议的操作:读取文件,然后使用您自己的脚本中的globals exec 它:

with open('another.py') as f:
    exec(f.read(), globals())

请注意,这将使sys.argv 保持不变。当然,您可以先手动将其设置为其他值:

_argv = sys.argv
sys.argv = ['args', 'i', 'want', 'it', 'to', 'see']
try:
    with open('another.py') as f:
        exec(f.read(), globals())
finally:
    sys.argv = _argv

如果您是从另一个模块而不是从您的顶级脚本执行此操作,那将无法正常工作,但稍作修改后,它将:

with open('another.py') as f:
    exec(f.read(), sys.modules['__main__'].__dict__)

但您最好创建一个干净的全局命名空间。脚本可能不希望让您的全局变量坐在那里——它可能会改变您不希望它改变的东西。这同样简单:

with open('another.py') as f:
    exec(f.read(), {})

(请注意,这仍会自动继承当前的builtins,这是您通常想要的。如果您出于某种原因不想要,请参阅exec 文档。)


如果您想保证执行它的方式与正常运行脚本的方式完全相同,请使用runpy 模块。

当你运行python -m another 时,它最终会做的是:

runpy.run_module(sys.argv[0], run_name="__main__", alter_sys=True)

所以,你可以手动做同样的事情:

runpy.run_module('another', run_name='__main__')

您是否要添加alter_sys=True 取决于您的目标。没有它,如果脚本尝试访问sys.argv(就像您的脚本一样)或sys.modules['__main__'],它将看到您的值,而不是它自己的值。


如果你想模拟python another.py,你需要使用importlib来创建一个完整的__spec__和相关的对象,然后调用runpy.run_path

【讨论】:

  • 非常感谢!非常全面,正是我想要的。
【解决方案2】:

您可以读取该文件并使用exec 以当前全局变量执行代码,以便__name__ == '__main__' 为真。

exec(open('file.py').read(), globals())

【讨论】: