【问题标题】:Run a Python script from another Python script, passing in arguments [duplicate]从另一个 Python 脚本运行 Python 脚本,传入参数 [重复]
【发布时间】:2010-09-23 19:31:11
【问题描述】:

我想从另一个 Python 脚本运行一个 Python 脚本。我想像使用命令行一样传递变量。

例如,我将运行我的第一个脚本,该脚本将遍历值列表 (0,1,2,3) 并将这些值传递给第二个脚本 script2.py 0 然后 script2.py 1 等。

我发现Stack Overflow question 1186789 是一个类似的问题,但是 ars 的答案调用了一个函数,因为我想运行整个脚本,而不仅仅是一个函数,而 balpha 的答案调用了脚本但没有参数。我将其更改为以下内容作为测试:

execfile("script2.py 1")

但它没有正确接受变量。当我在 script2.py 中打印出sys.argv 时,它是对第一个脚本“['C:\script1.py'] 的原始命令调用。

我真的不想更改原始脚本(即我的示例中的 script2.py),因为我不拥有它。

我认为一定有办法做到这一点;我只是很困惑你是怎么做到的。

【问题讨论】:

  • 如果 os.system 对您来说不够强大,可以使用 the subprocess module
  • 问题是你是知道脚本的名字(然后导入它)还是在编程时不知道脚本的名字(然后使用subprocess.call)。在第二种情况下,这个问题也不会重复。因为问题没有说清楚,所以也不是很好。
  • @Trilarion:错了。你可以导入一个 python 模块,即使它的名字是在运行时生成的。
  • @Trilarion:为什么要覆盖它?两个问题中的名称都是固定的。无论如何,语句 “如果您在编程时不知道脚本的名称(然后使用 subprocess.call)。” 无论如何都是错误的。如果您有新问题; ask.
  • @Oli4 “肯定”是一个强词。需要详细说明吗?我看到 subprocess.call() 解决方案接受传递多个命令行参数。我看到在定义 main() 函数的情况下提到了import(它对 OP 没有帮助,但对于许多其他有类似问题的人来说,这是正确的方法)。我看到 Python 2 的 execfile() 使用了你放入 sys.argv 的任何内容(诚然,最后一点没有明确提到)——初学者应该忽略这个选项。甚至还有一个带有多个参数的显式 os.system() 答案(此处接受的答案)。

标签: python


【解决方案1】:

尝试使用os.system

os.system("script2.py 1")

execfile 不同,因为它被设计为在 current 执行上下文中运行一系列 Python 语句。这就是为什么 sys.argv 没有为你改变。

【讨论】:

  • 我相信通常使用subprocess.Popen 比使用os.system 更可取:docs.python.org/library/subprocess.html#replacing-os-system
  • 是的,这就是os.system 的帮助所说的。但是,对于简单的用途,os.system 是完成工作的最简单方法。当然,这取决于您的需求。
  • 你必须添加python才能运行脚本:os.system("python script2.py 1")
  • @macdonjo:不,os.system() 调用会等到您调用的对象完成后再继续。您可以使用subprocess.Popen() 并自己管理新进程,或者使用multiprocessing 模块或其他各种解决方案。
  • 我遇到了问题sh: 1: *.py: not found。添加 python 然后它就可以工作了,即os.system("python script2.py 1").
【解决方案2】:

理想情况下,您要运行的 Python 脚本将在接近尾声时使用如下代码设置:

def main(arg1, arg2, etc):
    # do whatever the script does


if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2], sys.argv[3])

换句话说,如果模块是从命令行调用的,它会解析命令行选项,然后调用另一个函数main() 来完成实际工作。 (实际参数会有所不同,解析可能会更复杂。)

但是,如果您想从另一个 Python 脚本调用这样的脚本,您可以简单地 import 它并直接调用 modulename.main(),而不是通过操作系统。

os.system 可以,但这是一种迂回(读作“慢”)的方式,因为您每次都在启动一个全新的 Python 解释器进程,而无需葡萄干。

【讨论】:

  • 回复:“没有葡萄干。”这不是错误。然而,有趣的是,不熟悉 Futurama 的人在一个随机的 Stack Overflow 问题中“纠正”它需要多长时间:两年零三个月。 :-)
  • 我嘲笑“没有葡萄干”只是因为这是一个荒谬的错字,然后看到你的评论并在 YouTube 上找到了一个剪辑。更有趣。
  • 我有一个没有 main 的脚本,但能够像这样引入: 1. 将函数定义和独立语句分开 2. 在“if name 下进行参数解析...”第 3 节。在 def main(...) 下缩进其余语句,并让该逻辑对方法参数进行操作。然后我就可以从另一个脚本调用 main 方法(例如:单元测试)
  • 将近 5 年后,我们又来了,我很高兴从 Futurama 那个 Fry 困惑的大脑中找到你的引述。
  • 哇,2 年……一个无法提高的时间长度!
【解决方案3】:

这本质上是错误的做法。如果您从另一个 Python 脚本运行 Python 脚本,您应该通过 Python 而不是通过操作系统进行通信:

import script1

在理想情况下,您将能够直接调用script1 内部的函数:

for i in range(whatever):
    script1.some_function(i)

如有必要,您可以破解sys.argv。有一种使用上下文管理器的简洁方法可以确保您不会进行任何永久性更改。

import contextlib
@contextlib.contextmanager
def redirect_argv(num):
    sys._argv = sys.argv[:]
    sys.argv=[str(num)]
    yield
    sys.argv = sys._argv

with redirect_argv(1):
    print(sys.argv)

我认为这比将所有数据传递给操作系统并返回更好;太傻了。

【讨论】:

  • 这可能是“错误”的事情,但是如果您需要引用的脚本没有 main 或函数怎么办......导入将在导入时执行脚本,这可能不是您想要的(并且您不想重构它,因为人们也在按原样使用该脚本)。 os/subprocess 可以处理这种情况
  • 是的......但这是一个不同的问题 IMO!
  • 多线程脚本不会失败吗?
  • 从更高层次的角度来看,将这种策略称为“错误”是“错误的”。当系统扩大规模时,对组件内部工作的详细了解成为一个越来越大的问题——用 Python 编写的程序可能会用另一种语言重新设计,并且使用操作系统的通用进程通信工具可以提供很多东西作为一种策略。
  • ... 那么依赖关系呢?如果每个脚本都有自己的依赖项,为什么第一个脚本应该知道第二个脚本的所有依赖项?从架构的角度来看,错误的是在python中直接调用导入(恕我直言)
【解决方案4】:

子流程模块:
http://docs.python.org/dev/library/subprocess.html#using-the-subprocess-module

import subprocess
subprocess.Popen("script2.py 1", shell=True)

有了这个,你还可以重定向标准输入、标准输出和标准错误。

【讨论】:

【解决方案5】:

我认为好的做法可能是这样的;

import subprocess
cmd = 'python script.py'

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate() 
result = out.split('\n')
for lin in result:
    if not lin.startswith('#'):
        print(lin)

根据文档 subprocess 模块允许您生成新进程,连接到它们的输入/输出/错误管道,并获取它们的返回码。该模块打算替换几个旧模块和功能:

os.system
os.spawn*
os.popen*
popen2.*
commands.*

使用communicate() 而不是.stdin.write、.stdout.read 或.stderr.read 以避免由于任何其他OS 管道缓冲区填满并阻塞子进程而导致的死锁。 Read Here

【讨论】:

    【解决方案6】:
    import subprocess
    subprocess.call(" python script2.py 1", shell=True)
    

    【讨论】:

    • 您可能希望扩展您的答案,以解释为什么这是比此处提供的其他一些答案更好的选择。
    • 如何传递参数而不是字符串,例如列表?除了单独传递每个元素之外,还有其他选择吗?
    • 除非必要,否则不要使用 shell=True。
    猜你喜欢
    • 1970-01-01
    • 2017-03-30
    • 2015-03-11
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    • 2021-01-24
    相关资源
    最近更新 更多