我想从另一个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),因为我不拥有它。
我想一定有办法做到这一点,我只是不明白你是怎么做到的。
- 的问题是,如果你知道名字的乐队(进口的脚本,然后它)或如果你不知道名字的脚本,在programming时间(然后使用subprocess.call)。在第二个案例,这个问题也就不在重复的形式。因为的问题不能使它清晰,它的也不是真的一个很好的。
- trilarion @:错了。你可以进口的Python模块,即使如果其名称也产生runtime美元。
- @ j.f.sebastian好吧。作为一个光的话:这侧的方式也不是真的好,出口由任何答案或睾丸在联问题,除了部分在stackoverflow.com / / / 1186840 1536976。
- trilarion @:为什么要把它所有的出口吗?的名称是固定在这两个问题。无论如何,"声明",如果你不知道名字的脚本,在programming时间(然后使用subprocess.call)。regardless"是错误的。如果你有一个新的问题;问。
- @ j.f.sebastian同意了。我没有任何问题吧。如果我来了一个我会surely问。
- oli4 @"绝对是"太强的话。护理到elaborate吗?我看到subprocess.call()的解决方案,accepts经过多个命令行arguments。我看到import被mentioned为例在大街(功能)的定义(它不会帮助OP,但它也是正确的方式为许多其他的人与similar问题)。我看到execfile(2)对Python的用途,无论你放进sys.argv(admittedly,最后一位是不mentioned explicitly)-这个选项应该ignored by beginners。有没有一个明确的答案os.system()与多个arguments(答案,接受睾丸)。
- 你的elaboration @ j.f.sebastian后,我到tempted同意你。即使,虽然其他的问题并不是explicitly specify技术送arguments或那个做以下的问题,是indeed similar。有时通过要求不同的解决方案出现的问题differently AS chrisadams的回答我的问题solved。我为我的apologize earlier声明说这indeed不重复的形式,和谢谢你。
尝试使用os.system:
1
| os.system("script2.py 1") |
execfile是不同的,因为它是为在当前执行上下文中运行一系列python语句而设计的。这就是为什么sys.argv没有为你改变的原因。
- 我认为使用subprocess.Popen比使用os.system更可取:docs.python.org/library/subprocess.html替换OS系统。
- 是的,这正是帮助os.system所说的。然而,对于简单的使用,os.system是完成工作的最简单方法。当然,这取决于你的需求。
- 还可以使用子进程。请检查_call()。
- 必须添加python才能运行脚本:os.system("python script2.py 1")。
- 所以如果我想启动5个线程,我只需将该行粘贴5次到一个文件中,然后从cron调用该文件?
- @麦当乔:不,在继续之前,os.system()调用会一直等到您调用的内容完成。您可以自己使用subprocess.Popen()和管理新流程,也可以使用multiprocessing模块或其他各种解决方案。
- 不过,这会等待回调,我认为您需要使用子进程
- @Greghewgill-是否有任何动态方法来传递os.system("script2.py myvariable")中变量的value?(注:myvariable不断变化,无法传递静态值)
- @H.U.:有关具体帮助,请参见将用户设置的变量作为os.system()命令的参数传递。
- 我遇到了一个问题。添加python,然后它就可以工作了,即os.system("python script2.py 1")。
- @sparkandshine:在最初的问题中,script2.py是可执行的。如果它不是可执行的,你需要做你所说的。最好是使用sys.executable,它是当前python可执行文件的名称(如果它与默认的不同)。比如:os.system(sys.executable +" script2.py 1")。
- @对我来说,python脚本的权限是755,script2.py以#!/usr/bin/env python开头。顺便说一句,os.system(sys.executable +" script2.py 1")也发生在sh: 1: *.py: not found上。
这从本质上来说是错误的。如果从另一个python脚本运行python脚本,则应通过python而不是通过操作系统进行通信:
在理想情况下,您可以直接调用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) |
我认为这比把你所有的数据都传回操作系统要好,这太愚蠢了。
- 这可能是"错误"的事情,但如果需要引用的脚本没有主脚本或函数,该怎么办?导入将在导入时执行脚本,这可能不是您想要的(而且您不想重构它,因为人们也按原样使用该脚本)。操作系统/子流程可以处理这种情况
- 是真的…但在我看来,这是另一个问题!
- 对于多线程脚本,这不会失败吗?
- @马里奥维拉斯可能,是的。
- 您的方法不适用于多线程。我试图同时运行同一个文件10次。
- @丹斯:确实有效。你可以用multiprocessing。
- 从更高的层次来看,把这种策略称为"错误"是"错误的"。当系统扩展时,对组件内部工作的详细了解就变成了一个越来越大的问题——用python编写的程序可能会被重新设计成另一种语言,并且使用操作系统的通用进程通信工具作为一种策略有很多要提供的。
- 值得注意的是,您可以直接在代码中间导入,而不必将其放在顶部,@dans
- …那么依赖性呢?如果每个脚本都有自己的依赖项,为什么第一个脚本应该知道sencond的所有脚本依赖项?从体系结构的角度来看,错误的是调用python中的直接导入(imho)
理想情况下,您要运行的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解释器进程,而不需要任何理由。
- 回复:"没有葡萄干。"这不是一个错误。然而,有趣的是,在一个随机的堆栈溢出问题(两年零三个月)中,看到一个不熟悉Futurama的人需要多长时间来"纠正"它。-)
- 我嘲笑"没有葡萄干"只是因为它是一个可笑的打字错误,然后看到你的评论,在YouTube上找到了一个剪辑。甚至更有趣。
- 我有一个没有主旨的剧本,但我可以这样介绍:1。单独的函数defs和独立的语句2。在"if name…"第3节下进行参数分析。在def main(…)下缩进其余语句,并让该逻辑对方法参数进行操作。然后我可以从另一个脚本调用主方法(例如:单元测试)
- 是的,python真的让重构变得非常简单。我自己做过不止一次类似的事情!
- 如果主程序有可选参数,这种方法对我不起作用。这里我得到"列表索引超出范围"。最好有一个Main(sys.argv)并主要处理参数列表
- "如果主程序有可选参数,这种方法对我不起作用"——如果您的解析非常复杂,那么您无论如何都应该使用argparse模块。
- 近5年后,我们又来了,我很高兴看到你从Futurama那个头脑混乱的fry那里引用的话。
子流程模块: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) |
- 您可能希望扩展您的答案,以解释为什么这是一个比这里提供的其他一些答案更好的选择。
- 如何传递参数而不是字符串,例如list?除了单独传递每个元素,还有其他选择吗?
- 除非必要,否则不要使用shell=true。
如果os.system不够强大,那么就有子进程模块。