what happens to Popen()'s parent-side file descriptors?

Nobody nobody at nowhere.com
Fri Oct 15 08:27:09 CEST 2010

On Thu, 14 Oct 2010 08:48:45 -0700, Roger Davis wrote:

> On a related point here, I have one case where I need to replace the
> shell construct
>    externalprog <somefile >otherfile
> I suppose I could just use os.system() here but I'd rather keep the
> Unix shell completely out of the picture (which is why I am moving
> things to Python to begin with!), so I'm just doing a simple open() on
> somefile and otherfile and then passing those file handles into
> Popen() for stdin and stdout. I am already closing those open()ed file
> handles after the child completes, but I suppose that I probably
> should also explicitly close Popen's p.stdin and p.stdout, too. (I'm
> guessing they might be dup()ed from the original file handles?)

p.stdin will be None unless you use stdin=subprocess.PIPE; similarly for

Another gotcha regarding pipes: the reader only sees EOF once there are no
writers, i.e. when the *last* writer closes their end.

If Python has a descriptor for the write end of a pipe, any child process
will inherit it unless you use close_fds=True or close it via a function
specified by the preexec_fn argument. Allowing it to be inherited can
prevent the reader from seing EOF on the pipe.

E.g. if you do:

	p1 = Popen(..., stdin = PIPE, stdout = PIPE)
	p2 = Popen(..., stdin = p1.stdout)

p2 will inherit p1.stdin (that's the write end) from Python. Subsequently
calling p1.stdin.close() *won't* cause p1 to see EOF on its stdin because
p2 still has its inherited copy of the descriptor open.

On Windows, only stdin, stdout and stderr are inherited, so this isn't an
issue there.

More information about the Python-list mailing list