An interesting question. The simplest solution would be similar to what Pete suggest. Just print the escape codes before running the function to each of stderr and stdout. However, if both stderr and stdout feed the same terminal, as is usually the case, they will interfere.
So, an alternative solution is to monkey-patch stdout and stderr with a tiny wrapper that enables the color for the duration of each write, taking care to do this only if we're in a terminal (and not piped).
#!/usr/bin/python2
import sys
def colorize(stdoutColor, stderrColor):
defaultColor = '33[0;0m'
def applyColorize(f):
class colorWrapper(object):
def __init__(self, wrapee, color):
self.wrapee = wrapee
self.color = color
def __getattr__(self, attr):
if attr == 'write' and self.wrapee.isatty():
return lambda x: self.wrapee.write(self.color + x + defaultColor)
else:
return getattr(self.wrapee, attr)
def wrapper(*args, **kwds):
oldStdout = sys.stdout
oldStderr = sys.stderr
sys.stdout = colorWrapper(oldStdout, stdoutColor)
sys.stderr = colorWrapper(oldStderr, stderrColor)
try:
f(*args, **kwds)
finally:
sys.stdout = oldStdout
sys.stderr = oldStderr
return wrapper
return applyColorize
greenColor = '33[01;32m'
redColor = '33[01;31m'
def foo():
print "I'm ordinary and boring!"
print >> sys.stderr, 'Writing to stderr!'
@colorize(greenColor, redColor)
def colorFoo():
print "I'm colorful and exciting!"
print >> sys.stderr, 'Writing to stderr!'
if __name__ == '__main__':
foo()
colorFoo()
foo()
This can still be polished a bit, but it should do the job in most cases and cleans up after itself properly. Of course, keep in mind I'm using shell-specific escape codes. If you want portability, you'll have to replace the escape code writes with calls to a portable terminal control module.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…