7

When dealing with open files, Python has the with syntax that makes sure the file closes when leaving the block - regardless of exceptions etc.

with open('foo.txt') as f:
    foo = f.read()

Since processes are resources too, I was wondering: is something similar possible or recommended when using Popen? For example, should Popen.kill(); Popen.communicate() be run in a finally clause - assuming I don't mind blocking until the process finishes?

1
  • 1
    If you were running a version pre python 3.2. you could just define a class with the __enter__ and __exit__ magic methods to use with. Commented May 24, 2015 at 7:26

3 Answers 3

6

Starting from Python 3.2 Popen is a context manager.

from the docs:

Popen objects are supported as context managers via the with statement: on exit, standard file descriptors are closed, and the process is waited for.

This should do pretty much what you want.

This is the relevant part from subprocess.py from the standard lib in Python 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()

Now you can do in 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)
Sign up to request clarification or add additional context in comments.

3 Comments

OK, cool. So it sounds like it's not a bad idea to do it in Python 2.7 as well, using try...finally
I added a Python 2.7 version by copying the code from python 3.4. Might need some testing though. ;)
@z0r: there is subprocess32 module that you can install on Python 2.7 (it provides other improvements too. Though it might not work on non-POSIX systems).
5

For 2.7 you could also use the @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()

e.g:

with manage_process(Popen(['ls'])) as p:
    print(p)

Comments

2

You can add just two custom methods to any class to implement comptability with with statement.

class CustomObject(object):
    def __enter__(self):
        """ This method execudes when entering block. """
        return thing_you_want_to_use

    def __exit__(self, type, value, traceback):
        """ This method execudes on block exit. """
        # Tear things down.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.