在去除ANSI颜色代码的同时打印到STDOUT和日志文件中

10

我有以下函数用于给屏幕消息上色:

def error(string):
    return '\033[31;1m' + string + '\033[0m'

def standout(string):
    return '\033[34;1m' + string + '\033[0m'

我使用它们的方式如下:
print error('There was a problem with the program')
print "This is normal " + standout("and this stands out")

我希望能够将输出记录到文件中(除了STDOUT),但不带ANSI颜色代码,希望不必为每个print语句添加第二个“logging”行。

原因是如果简单地使用python program.py > out,则文件out将包含ANSI颜色代码,如果在纯文本编辑器中打开,则看起来很糟糕。

有什么建议吗?

3个回答

11

sys.stdout.isatty 函数可能会有所帮助:

from sys import stdout

def error(string, is_tty=stdout.isatty()):
    return ('\033[31;1m' + string + '\033[0m') if is_tty else string

def standout(string, is_tty=stdout.isatty()):
    return ('\033[34;1m' + string + '\033[0m') if is_tty else string

实际上这是我能想到的几个用默认参数的情况之一,但默认参数在Python中是在编译时而不是像C++一样在运行时计算的...

而且如果你真的需要,行为可以被显式地覆盖,尽管这不允许你在重定向stdout时操纵stdout本身。你没有使用logging模块有任何原因吗(也许你不知道它)?


非常好的答案 - 这可能正是我需要的。我实际上正在使用日志记录模块,但希望让用户有选择地重定向输出并获得可读的文件。日志本身由日志记录模块创建(使用您的方法,我很可能会得到我想要的结果)。 - Escualo
我刚刚测试了你的方法,它完全按照预期工作。非常感谢! - Escualo

7
如果您希望既将内容打印到终端又记录到日志文件中,我建议使用logging模块。您甚至可以定义一个自定义格式化程序,以便记录到文件时可以清除终端代码:
import optparse
import logging

def error(string):
    return '\033[31;1m' + string + '\033[0m'

def standout(string):
    return '\033[34;1m' + string + '\033[0m'

def plain(string):
    return string.replace('\033[34;1m','').replace('\033[31;1m','').replace('\033[0m','')

if __name__=='__main__':
    logging.basicConfig(level=logging.DEBUG,
                        format='%(message)s',
                        filemode='w')
    logger=logging.getLogger(__name__)    
    def parse_options():    
        usage = 'usage: %prog [Options]'
        parser = optparse.OptionParser()
        parser.add_option('-l', '--logfile', dest='logfile', 
                          help='use log file')
        opt,args = parser.parse_args()
        return opt,args
    opt,args=parse_options()
    if opt.logfile:
        class MyFormatter(logging.Formatter):
            def format(self,record):
                return plain(record.msg)
        fh = logging.FileHandler(opt.logfile)
        fh.setLevel(logging.INFO)
        formatter = MyFormatter('%(message)s')
        fh.setFormatter(formatter)
        logging.getLogger('').addHandler(fh)

    logger.info(error('There was a problem with the program'))
    logger.info("This is normal " + standout("and this stands out"))

test.py只会在终端打印输出。

test.py -l test.out则既会在终端打印,也会将输出写入test.out文件。

所有情况下,终端输出的文本都有颜色代码,而日志输出则没有。


2
下面是unubtu的回答,很好,但我认为MyFormatter需要进行轻微修改,以强制在format()方法中进行格式化。
class MyFormatter(logging.Formatter):
        def format(self,record):
            msg = super(MyFormatter, self).format(record)
            return plain(msg)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接