从另一个Python脚本运行一个Python脚本

Run a Python script from another Python script, passing in arguments

本问题已经有最佳答案,请猛点这里访问。

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

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

我发现堆栈溢出问题1186789是一个类似的问题,但是ars的答案调用了一个函数,在这个函数中,我想运行整个脚本,而不仅仅是一个函数,而balpha的答案调用了脚本,但没有参数。我把这个改成了下面这样的测试:

1
execfile("script2.py 1")

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

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

我想一定有办法做到这一点,我只是不明白你是怎么做到的。


尝试使用os.system

1
os.system("script2.py 1")

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


这从本质上来说是错误的。如果从另一个python脚本运行python脚本,则应通过python而不是通过操作系统进行通信:

1
import script1

在理想情况下,您可以直接调用script1中的函数:

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

如有必要,您可以黑客sys.argv。使用上下文管理器可以很好地做到这一点,以确保您不会做出任何永久性的更改。

1
2
3
4
5
6
7
8
9
10
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)

我认为这比把你所有的数据都传回操作系统要好,这太愚蠢了。


理想情况下,您要运行的python脚本将在结尾处设置如下代码:

1
2
3
4
5
6
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解释器进程,而不需要任何理由。


子流程模块:http://docs.python.org/dev/library/subprocess.html使用子流程模块

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

这样,您还可以重定向stdin、stdout和stderr。


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

1
2
3
4
5
6
7
8
9
10
import subprocess
cmd = 'python script.py'

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

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

1
2
3
4
5
os.system
os.spawn*
os.popen*
popen2.*
commands.*

使用communication()而不是.stdin.write、.stdout.read或.stderr.read以避免由于任何其他OS管道缓冲区填充和阻塞子进程而导致死锁。在这里阅读


1
2
import subprocess
subprocess.call(" python script2.py 1", shell=True)


如果os.system不够强大,那么就有子进程模块。