使用Python子进程调用来调用Python脚本

61

我有一个Python脚本需要调用同一目录下的另一个Python脚本。我这样做了:

from subprocess import call
call('somescript.py')

我遇到了以下错误:

call('somescript.py')
File "/usr/lib/python2.6/subprocess.py", line 480, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child

raise child_exception
OSError: [Errno 2] No such file or directory

我有一个名为somescript.py的脚本,它与这个文件夹放在同一级目录下。我在这里漏掉了什么吗?


1
你的 PATH 中是否包含 .?somescript.py 是否可执行? - Wooble
1
你为什么要尝试执行它?为什么不使用“import”呢? - tMC
1
@wooble 是的。它在路径中并且也是可执行文件。是的,我也可以导入它。但无论如何,我想知道我在这里做错了什么,因为我认为这应该可以工作。 - user514946
2
为什么不导入?有很多原因:即使已经导入,也可以真正执行;具有__name__ == '__main__';可以多次运行。 - Tomasz Gandor
另外,如果它不是Python 2,并且在同一个目录中的其他脚本 - 它不会简单地导入。您可能需要将其目录添加到sys.path,但出于许多原因(例如名称冲突),您可能不想这样做,其中包括安全性。 - Tomasz Gandor
10个回答

62
如果'somescript.py'不是你通常可以直接从命令行执行的内容(即$: somescript.py可行),那么你不能直接使用call来调用它。
请记住,Popen的工作方式是第一个参数是要执行的程序,其余的是传递给该程序的参数。在这种情况下,程序实际上是python,而不是你的脚本。所以以下代码将按照你的期望工作:
subprocess.call(['python', 'somescript.py', somescript_arg1, somescript_val1,...])

这个正确地调用了Python解释器,并告诉它使用给定的参数来执行你的脚本。
请注意,这与上面的建议不同。
subprocess.call(['python somescript.py'])

这将尝试执行名为 python somscript.py 的程序,显然不存在。

call('python somescript.py', shell=True)

也可以工作,但是使用字符串作为输入调用不是跨平台的,如果你不是在构建字符串的人,这样做是危险的,并且应该尽可能避免。


我遇到了这个问题,但是脚本的路径在我的basrc文件中,所以我可以通过终端调用它作为myscript(args)。但是当我尝试从Python执行上述操作时,我会收到一个“未找到”错误? - Rankinstudio
1
根据Python 3.5中的文档,现在可以使用run()代替call() - Bill
这有点简单化了 - 为什么只是 python - 它是否在您的路径上?它将是您正在运行的相同解释器吗? - Tomasz Gandor
3
وˆ‘ه»؛è®®ه°†'python'و”¹ن¸؛sys.executable(https://dev59.com/wXE85IYBdhLWcg3w1HKF, https://dev59.com/ZW025IYBdhLWcg3wkW4F),è؟™و ·ه°±هڈ¯ن»¥ن؛†م€‚ - Tomasz Gandor

8

Windows?Unix?

在Unix中,需要使用shebang和exec属性才能正常工作:

#!/usr/bin/env python

作为脚本的第一行:
chmod u+x script.py

在命令行或者

call('python script.py'.split())

如前所述。

如果您在“call”调用中添加了 shell=True参数,Windows应该可以正常工作。


9
在非Windows系统上,call('python script.py')无法正常工作。应该使用check_call([sys.executable or 'python', '/path/to/script.py'])。如果指定了python可执行文件,则不需要shebang和可执行权限。 - jfs
sys.executable 应该足够处理所有正常情况。 - Stuart Axon

4

看看这个。

from subprocess import call 
with open('directory_of_logfile/logfile.txt', 'w') as f:
   call(['python', 'directory_of_called_python_file/called_python_file.py'], stdout=f)

4
import subprocess
command = 'home/project/python_files/run_file.py {} {} {}'.format(
        arg1, arg2, arg3) # if you want to pass any arguments
p = subprocess.Popen(
        [command],
        shell=True,
        stdin=None,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        close_fds=True)
out, err = p.communicate()

3

subprocess.callsubprocess.Popen需要相同的参数,即字符串列表(在C中为argv),而不是单个字符串。

很可能你的子进程尝试以参数“o”、“m”、“e”等来运行“s”。


2
如果你使用的是Linux/Unix系统,你可以避免使用call()函数,从而避免执行一个全新的Python可执行文件及其环境。
import os

cpid = os.fork()
if not cpid:
    import somescript
    os._exit(0)

os.waitpid(cpid, 0)

就它的价值而言。


1
仅限*nix:使用fork,您将从父进程Python解释器(包括所有现有的导入等)继承。如果您想要一个全新的解释器,这不是一个好选择。请查看diff fork / exec unix系统调用。 - Nicolae Dascalu
subprocess 模块在 POSIX 系统上使用 fork/exec,在 Windows 上使用 CreateProcess。如果要运行 Python 脚本,则无需直接使用 fork - jfs
这里有很多假设。顶层脚本的操作方式与导入的模块不同。如果它在 if "__name__" == "__main__": 子句中完成工作怎么办?还有在分叉后需要为新进程执行的所有其他任务呢?也许它会起作用……但是这里有很多注意事项。 - tdelaney

1

有什么问题

import sys
from os.path import dirname, abspath

local_dir = abspath(dirname(__file__))
sys.path.append(local_dir)

import somescript

或者更好的方法是将功能封装在一个函数中,例如baz,然后执行以下操作。
import sys
from os.path import dirname, abspath

local_dir = abspath(dirname(__file__))
sys.path.append(local_dir)

import somescript
somescript.baz()

看起来有很多脚本开始Python进程或分叉,这是必需的吗?


0
def main(argv):
    host = argv[0]
    type = argv[1]
    val = argv[2]

    ping = subprocess.Popen(['python ftp.py %s %s %s'%(host,type,val)],stdout = subprocess.PIPE,stderr = subprocess.PIPE,shell=True)
    out = ping.communicate()[0]
    output = str(out)
    print output

0

子进程调用是一种非常字面意义的系统调用。它可以用于任何通用进程……因此不知道如何自动处理Python脚本。

尝试

call ('python somescript.py')

如果那样不起作用,你可能想尝试绝对路径,并/或者检查Python脚本的权限...典型的有趣问题。

0

首先,检查somescript.py是否可执行并以#!/usr/bin/python开头。 如果是这样,那么您可以使用subprocess.call('./somescript.py')

或者正如另一个答案所指出的那样,您可以执行subprocess.call(['python', 'somescript.py'])


只是一个随机的指针:我发现使用 #!/usr/bin/env python 很有用,这样如果一个模块已经被加载,你就会自动运行已加载的 Python 版本。 - Vorticity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接