I have two suggestions for improvement:
(1) instead of sys.std{out,in}.fileno() you can just use 1 and 0 --
this is safer since the calling program may have assigned to sys.stdin
or sys.stdout, but the exec really wants the file descriptors numbered
0 (stdin) and 1 (stdout). (There may be symbolic constants for these
in the POSIX standard, but they will have these values, if only
because too much existing code uses them.)
(2) Instead of opening /dev/null and dup2'ing the R file descriptor in
it, you can use self.file = posix.fdopen(self.R, 'r'). This does what
you want without tricks, and may even be safe: some versions of stdio
choose an optimal buffer size depending on the file system on which
the file resides; I assume thsi will usually happen on the first
write, but conceptually you're doing something undefined.
(...Do I hear the Spanish inquisition entering...?)
(3) You should surround the execv with a try: ... except posix.error:
... and in the except clause print the error and call
posix._exit(127). Otherwise the forked main program will print the
traceback, and possibly continue to run if it catches the exception.
On second thought, everything in the child should be surrounded with
an unqualified try: ... except: ..., just in case something nasty
happens like running out of file descriptors (yes, this will happen,
if you create a lot of these sessions and happen to leave the objects
lingering around...).
But then, with these changes your program wouldn't even qualify for
the opening rounds of the obfuscated Python contest... :-)
--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>
URL: <http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>