使用Python的subprocess.Popen时的异常处理

z0r*_*z0r 6 python subprocess exception-handling

在处理打开的文件时,Python的with语法确保文件在离开块时关闭 - 无论异常等.

with open('foo.txt') as f:
    foo = f.read()
Run Code Online (Sandbox Code Playgroud)

由于流程也是资源,我想知道:使用时是否有类似的可能或建议Popen?例如,应该Popen.kill(); Popen.communicate()在一个finally子句中运行- 假设在进程完成之前我不介意阻塞?

Mik*_*ler 6

从Python 3.2开始Popen是一个上下文管理器.

来自文档:

通过with语句支持Popen对象作为上下文管理器:退出时,将关闭标准文件描述符,并等待进程.

这应该做你想要的.

这是subprocess.pyPython 3.4中标准库的相关部分:

def __enter__(self):
    return self

def __exit__(self, type, value, traceback):
    if self.stdout:
        self.stdout.close()
    if self.stderr:
        self.stderr.close()
    if self.stdin:
        self.stdin.close()
    # Wait for the process to terminate, to avoid zombies.
    self.wait()
Run Code Online (Sandbox Code Playgroud)

现在你可以用Python 2.7了

from subprocess import Popen

class MyPopen(Popen):

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        if self.stdout:
            self.stdout.close()
        if self.stderr:
            self.stderr.close()
        if self.stdin:
            self.stdin.close()
        # Wait for the process to terminate, to avoid zombies.
        self.wait()

if __name__ == '__main__':
    with MyPopen(['ls']) as p:
        print(p)
Run Code Online (Sandbox Code Playgroud)


Pet*_*ood 5

对于 2.7,您还可以使用@contextlib.contextmanager

import contextlib

@contextlib.contextmanager
def manage_process(process):
    try:
        yield process
    finally:
        for stream in [process.stdout, process.stdin, process.stderr]:
            if stream:
                stream.close()
        process.wait()
Run Code Online (Sandbox Code Playgroud)

例如:

with manage_process(Popen(['ls'])) as p:
    print(p)
Run Code Online (Sandbox Code Playgroud)