2010-09-23 270 views
217

我想从另一个Python脚本运行Python脚本。我想要像使用命令行一样传递变量。从另一个python脚本运行python脚本,传入参数

例如,我会跑我的,将通过值(0,1,2,3)的列表迭代第一个脚本,并通过那些到第二脚本script2.py 0然后script2.py 1

我发现SO 1186789这是一个类似的问题,但阿尔斯的答案调用函数,因为我想运行整个脚本不只是一个函数,和balpha的答案调用脚本,但没有参数。我将其改为如下所示的测试:

execfile("script2.py 1") 

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

我不是真的想要更改原始脚本(即script2。 。在我的例子PY),因为我不拥有它

我想一定有办法做到这一点,我只是困惑,你是怎么做到的

+0

问题是如果您知道脚本的名称(然后导入它),或者如果您在编程时不知道脚本的名称(然后使用subprocess.call)。在第二种情况下,这个问题也不会重复。因为这个问题没有说清楚,所以也不是很好。 – Trilarion 2015-09-03 11:37:47

+0

@Trilarion:错了。你可以导入一个python模块,即使它的名字是在运行时生成的。 – jfs 2015-11-29 08:33:50

+0

@ J.F.Sebastian好的。作为一个方面的评论:这种方式并没有真正涵盖任何答案或链接的问题,部分在http://stackoverflow.com/a/1186840/1536976。 – Trilarion 2015-11-29 10:05:05

回答

238

尝试使用os.system

os.system("script2.py 1") 

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

+36

我相信通常最好在'os.system'上使用'subprocess.Popen':http://docs.python.org/library/subprocess.html#replacing-os-system。 – katrielalex 2010-09-23 20:15:15

+9

是的,这就是'os.system'的帮助所说的。然而,对于简单的用途来说'os.system'是完成工作的最简单的方法。当然,这取决于你的需求。 – 2010-09-23 20:39:35

+2

您也可以使用subprocess.check_call()。 – MarioVilas 2013-03-13 11:01:19

81

这本质上是错误的。如果您正在从另一个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) 

我认为这是优于将所有数据传递到操作系统并返回;这很愚蠢。

+9

这可能是“错误”的事情,但如果您需要引用的脚本没有主要或功能,那么该怎么办......导入会在导入时执行脚本,这可能不是您想要的你不想重构它,因为人们也是这样使用该脚本)。 os/subprocess可以处理这种情况 – 2012-08-21 15:33:11

+0

真的......但这是一个不同的问题IMO! – katrielalex 2012-08-21 16:08:28

+4

多线程脚本不会失败吗? – MarioVilas 2013-03-13 11:01:02

70

理想情况下,你要运行将被设置了这样的代码接近尾声的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解释器过程。

+9

回复:“没有葡萄干。”这不是一个错误。然而,看到不熟悉* Futurama *的人需要多长时间才能在一个随机堆栈溢出问题中“纠正”它:两年零三个月。 :-) – kindall 2012-12-29 18:30:49

+0

因为这是一个荒谬的错字,我嘲笑“没有葡萄干”,然后看到你的评论,并在YouTube上找到一个剪辑。更有趣。 – armani 2013-05-20 15:51:56

+0

我有一个没有main的脚本,但能够这样引入:1.分离函数defs和独立语句2.在“if __name __...”部分下执行参数解析3.在def下压缩其余语句main(...)并使该逻辑对方法参数进行操作。然后我可以从另一个脚本调用主要方法(例如:单元测试) – 2013-05-28 18:00:55

21
import subprocess 
subprocess.call(" python script2.py 1", shell=True) 
+14

您可能希望扩展您的答案,以解释为什么这是一个比这里介绍的其他答案更好的选项。 – 2013-11-12 12:29:15

+1

如何传递参数而不是字符串,例如列表?除了分别传递每个元素还有其他选择吗? – Michu93 2016-07-21 09:20:15

+0

除非必要,否则不要使用shell = True。 – 2017-10-09 19:29:06

25

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

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.* 

使用通信(),而不是.stdin.write,.stdout.read或.stderr.read避免死锁由于任何其他OS管缓冲器的填补和阻止儿童进程。 Read Here