【问题标题】:(python) colour printing with decorator in a function(python) 在函数中使用装饰器进行彩色打印
【发布时间】:2011-09-05 22:56:21
【问题描述】:

我怎样才能装饰一个函数,使它打印到stdout 的任何东西都是绿色,而它打印到stderr 的任何东西都是红色?我有可用的termcolor 模块。

Bonus karma:如何将参数传递给装饰器以指定颜色,默认为红色和绿色?

【问题讨论】:

  • 装饰器影响被装饰的功能,而不是完全不相关的功能,例如sys.stdout.write。定义write_to_stdout(line, color=GREEN) 并使用它代替print 要容易得多。您可以在函数内部替换标准输出,但这看起来很不合时宜并且会与线程中断。
  • @Jochen:在没有正确同步的情况下从多个线程打印到同一个流将导致输出混乱,无论 stdout 是否被覆盖,因此它是无关紧要的,并且创建一个特殊的 write_to_stdout() 函数不会解决从脚本调用的(Python)库打印到标准输出的情况。至于hackiness,每次使用管道时都会重定向stdout。这是一种完全正常的方法。

标签: python function decorator


【解决方案1】:

一个有趣的问题。最简单的解决方案类似于 Pete 的建议。只需在将函数运行到每个 stderr 和 stdout 之前打印转义码。但是,如果 stderr 和 stdout 都输入同一个终端,通常情况下,它们会干扰。

因此,另一种解决方案是使用小型包装器对标准输出和标准错误进行猴子补丁,该包装器在每次写入期间启用颜色,仅当我们在终端中(而不是管道)时才注意这样做。

#!/usr/bin/python2

import sys

def colorize(stdoutColor, stderrColor):
  defaultColor = '\033[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 = '\033[01;32m'
redColor = '\033[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()

这仍然可以稍微完善一下,但在大多数情况下它应该可以完成这项工作,并且可以自行清理。当然,请记住我使用的是特定于 shell 的转义码。如果您想要可移植性,则必须将转义代码写入替换为对便携式终端控制模块的调用。

【讨论】:

    【解决方案2】:

    这是我使用 termcolor 模块的代码:

    from termcolor import colored
    
    class ColoredOutput:
        def __init__(self, org_handle, color, on_color=None, attrs=['bold']):
            self.org_handle = org_handle
            def wrapper_write(x):
                return org_handle.write(colored(x, color=color, on_color=on_color, attrs=attrs))
            self.wrapper_write = wrapper_write
        def __getattr__(self, attr):
            return self.wrapper_write if attr == 'write' else getattr(self.org_handle, attr)
    
    if __name__ == '__main__':
        import sys
        import colorama   # I'm working under windows 7, so i need this module to enable terminal color
    
        colorama.init()
        sys.stderr = ColoredOutput(sys.stderr, 'red')
        print('This is a test string', file=sys.stderr)
    

    【讨论】:

      【解决方案3】:

      这适用于我在 Mac 的 Terminal.app 中的 Bash

      import sys
      green = '\033[01;32m'
      red = '\033[01;31m'
      
      sys.stdout.write(green+"Hello ")
      sys.stderr.write(red+"world!")
      

      【讨论】:

      • 你不需要取消转义后记吗?当你这样做时,所有终端输出保持绿色或红色
      • 你可以用'\033[0m'结束着色
      猜你喜欢
      • 2020-10-28
      • 1970-01-01
      • 2015-11-16
      • 1970-01-01
      • 2021-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      相关资源
      最近更新 更多