资讯详情

在Python中使用colorama库给输出添加颜色

📅 2026/10/11 13:30:55 | 华诺云谱 👁 阅读
在Python中使用colorama库给输出添加颜色
前言终端里给输出加颜色靠的是一串控制字符不是字体、不是样式表。最典型的一串长这样\033[31m。它由三部分组成——转义字符ESC八进制写作\033十六进制是0x1B、左方括号[、以及参数31m。终端读到这串东西不会把它当文字显示而是当成一条「接下来输出用红色」的指令。这就是第一个常见误解的来源颜色不是数据是给终端解析的控制码。同一段字符串输出到终端时是一条彩色文字重定向到文件时就成了文件里一排看不懂的原始字节。第二个误解是把colorama当成「调色板库」——它不是它的正经工作是让这些 ANSI 序列在 Windows 上也能生效官方描述很直接颜色常量只是「ANSI 转义序列的便捷简写刻意保持简陋」。本文先讲清 ANSI 转义序列本身再解释为什么老 Windows 控制台默认不认最后说明colorama到底做了什么、init()与just_fix_windows_console()的差别以及重定向到文件为什么会出现乱码。示例基于 Python 3.8 及以上colorama需要先pip install colorama本文按 0.4.6 的接口书写具体以该库官方文档为准。需要说明的是colorama本身也兼容 Python 2.7但 Python 2.7 已于2020 年 1 月 1 日停止维护本文一律使用 Python 3 的写法。最直观的一处差别是打印彩色文本老代码里的print Fore.RED 错误是 Python 2 的语句形式在 Python 3 里必须写成print(Fore.RED 错误)。一、ANSI 转义序列长什么样一个 SGRSelect Graphic Rendition选择图形再现序列的通用形状是ESC [ 参数 ; 参数 ... m其中ESC是单个控制字符。在 Python 字符串里它既可以写成八进制的\033也可以写成十六进制的\x1b——两者完全等价。后面的m表示「这是一条设置显示属性的指令」。常用的参数有代码含义类别0重置所有属性复位1加粗 / 高亮样式2变暗样式4下划线样式30–37前景色黑红绿黄蓝品青白前景39恢复默认前景色前景40–47背景色背景49恢复默认背景色背景90–97亮色前景前景所以\033[31m的意思是「前景设为红色」而\033[0m是「把一切都恢复默认」。多条参数可以用分号连起来例如\033[1;31m是「加粗的红色」。# 适用于 Python 3.8RED \033[31mRESET \033[0m# 只用标准库直接往终端写 ANSI 序列print(f{RED}这段字是红的{RESET}这段恢复默认)在类 Unix 的终端以及支持 ANSI 的现代 Windows 终端里这段会显示成红字。注意末尾一定要有复位序列否则「红色状态」会一直持续到后面所有输出直到有人把它关掉。二、为什么老 Windows 控制台默认不认ANSI 转义序列源自终端设备时代类 Unix 终端一直沿用。Windows 的老控制台conhost的旧行为在默认状态下不把ESC[...m当指令而是当成普通文本——于是你会看到←[31m这样的乱码ESC常被显示成一个左箭头或小方块。问题的关键在于Windows 早年的控制台是通过专门的 Win32 API设置文本属性、设置光标位置等来改颜色和位置的它根本没有「解析 ANSI 序列」这条路。要让彩色输出同时适配两边要么让 Windows 去理解 ANSI要么让程序检测平台、在 Windows 上改用 Win32 调用。现代 Windows 10 及以上的控制台已经内置了可开启的VT 序列处理能力colorama会去「翻开这个开关」。对更老的系统它的办法则是替换流对象。三、colorama 做了什么按官方文档的说法Colorama 让 ANSI 序列在 Windows 上也能工作做法是包裹wrapstdout把它里面的 ANSI 序列剥掉这些序列本来会显示成乱码再转换成相应的 win32 调用去改变终端状态。在其他平台上Colorama 什么都不做——因为那里本来就认识 ANSI。它对外提供了两套初始化接口# 适用于 Python 3.8colorama 0.4.6from colorama import just_fix_windows_consolejust_fix_windows_console()just_fix_windows_console()0.4.6 起提供只做「让 Windows 认识 ANSI」这一件事如果是在较新的 Windows 10 及以上、且 stdout/stderr 指向 Windows 控制台它就翻开内置 ANSI 支持如果是更老的 Windows它就把流包成能拦截 ANSI 序列、转成 Win32 调用的对象其余情况什么都不做。文档明确说它「多次调用是安全的」「在非 Windows 平台调用也是安全的只是不会有任何效果」「stdout/stderr 被重定向到文件时也不会对那个流做任何事」。另一套是更老、功能更多的init()# 适用于 Python 3.8from colorama import init, Fore, Back, Styleinit() # 默认 autoresetFalseprint(Fore.RED 红色文字)print(Back.GREEN 绿底文字)print(Style.DIM 暗淡文字)print(Style.RESET_ALL) # 复位前景、背景、亮度print(回到正常)它接受的常用关键字参数以官方文档为准参数默认作用autoresetFalse为True时每次print后自动复位stripNone按环境推断是否剥掉 ANSI 码convertNone按环境推断是否把 ANSI 码转成 win32 调用wrapTrue是否替换sys.stdout/sys.stderr文档给了两条关于默认推断的重要说明strip的默认行为是「在 Windows 上、或输出被重定向不是 tty时就剥掉」convert的默认行为是「在 Windows 上、且输出指向终端时转换」。autoresetTrue能省去每行结尾手写复位# 适用于 Python 3.8from colorama import init, Foreinit(autoresetTrue) # 每次 print 后自动回到默认颜色print(Fore.RED 红字)print(这行已经自动恢复默认颜色)颜色常量本身只是字符串可以直接看到它们的真面目# 适用于 Python 3.8from colorama import Fore, Back, Styleprint(repr(Fore.RED)) # \x1b[31mprint(repr(Back.GREEN)) # \x1b[42mprint(repr(Style.RESET_ALL)) # \x1b[0mFore与Back里各有BLACK、RED、GREEN、YELLOW、BLUE、MAGENTA、CYAN、WHITE、RESETStyle里有DIM、NORMAL、BRIGHT、RESET_ALL。此外还有一组LIGHT*_EX的浅色常量文档注明它们「支持得相当好但不是标准的一部分」。文档还特别提到Windows 上Style.DIM不被支持显示效果和普通文本一样。程序中途想停用用deinit()把stdout/stderr还原之后再想启用用reinit()它比重新init()便宜效果一样。文档提醒init()多次调用是不安全的可能叠出好几层包裹反而把 ANSI 支持弄坏这也是官方建议大多数用户直接用just_fix_windows_console()的原因。四、为什么重定向到文件会变成乱码把「颜色」这件事重新表述一遍你写出的\033[31m是五个字符ESC、[、3、1、m只不过终端会特殊对待它们。文件没有终端那种「解释控制序列」的能力它只会老老实实把这几个字节存下来。python color_demo.py out.txt # stdout 进文件python color_demo.py 2 err.txt # stderr 进文件打开out.txt你会看到类似这样的内容^[是把ESC显示出来的记法^[[31m这段字是红的^[[0m这段恢复默认这不是「编码错了」而是「本该被终端消费掉的控制码被原样保留了」。两种初始化方式在这里表现不同用just_fix_windows_console()时文档说它不会对重定向的流做任何事所以原始 ANSI 码就这样进了文件。用init()时strip的默认推断会「在输出被重定向不是 tty时剥掉 ANSI 码」你会得到纯文本代价是颜色信息也没了。想让输出「要么全彩、要么全无」就把判断权交给自己而不是靠推断# 适用于 Python 3.8colorama 0.4.6import sysfrom colorama import just_fix_windows_consolejust_fix_windows_console()# 自己判断只有连到终端时才上色use_color sys.stdout.isatty()RED \033[31m if use_color else RESET \033[0m if use_color else print(f{RED}重要提示{RESET}这一段在终端里是红的写进文件时是纯文本)sys.stdout.isatty()判断标准输出是不是连着一个终端。这是很多命令行工具的标准做法颜色是可选的呈现层不该污染要落盘的数据。常见坑点坑点 1以为\033[31m是「把颜色写进字符串」。❌ 把带 ANSI 码的字符串存进数据库、写进 CSV指望别处能显示红色。 ✅ 颜色只是给终端看的控制码要落盘、要传输时先剥掉或只在isatty()为真时才拼上。坑点 2忘了写复位序列。❌print(\033[31m错误)后不写\033[0m—— 后面所有输出都跟着变红。 ✅ 每段染色后补Style.RESET_ALL或init(autoresetTrue)让它自动收尾。坑点 3反复调用init()。❌ 在多个函数里各写一次init()—— 文档明确说多次调用不安全可能叠出多层包裹、把 ANSI 支持弄坏。 ✅ 只在程序入口调一次或用可重复安全调用的just_fix_windows_console()。坑点 4以为 colorama 在 Linux/macOS 上会「处理」颜色。❌ 期待它在非 Windows 上帮忙转换或剥除 —— 文档说在其他平台上它什么都不做转换行为主要发生在 Windows。 ✅ 跨平台的颜色策略自己控非 Windows 那边本来就用原生 ANSI按isatty()决定是否上色。坑点 5把init()的默认剥离行为当成「一定保留颜色」。❌ 把输出重定向到文件后发现颜色没了以为是 bug ——strip默认在重定向时会剥掉 ANSI 码。 ✅ 明确需求再定要保留原始码就别用会剥离的方式要干净文本就让它剥。坑点 6以为Style.DIM到处都有效果。❌ 在 Windows 上指望「暗淡文字」能看出来 —— 文档写明 Windows 不支持 ANSI 的 dim显示得和普通文本一样。 ✅ 重要信息别只靠 dim 区分改用颜色或明确的前缀文字。坑点 7拿LIGHT*_EX常量当标准 API 到处用。❌ 认为它们是稳定的一部分 —— 文档说它们「支持得相当好但不是标准的一部分」。 ✅ 只用Fore/Back的标准色与Style的四个常量浅色属于可选项用了就要接受兼容性风险。坑点 8把带色的日志直接写进文件。❌ 日志文件里满是^[[31m—— 排查问题时反而更难读。 ✅ 只在输出到终端时上色日志文件走纯文本两者分开判断或者在写文件前统一剥掉 ANSI 码。总结你会看到的东西它是什么怎么想\033[31m/\x1b[31mESC [31m的 SGR 序列五个字符给终端解释的指令\033[0m复位所有属性每段染色后都要有终端里的红字终端消费了控制码颜色来自终端不来自字符串本身文件里的^[[31m控制码被原样保留不是乱码是「没终端来消费它」just_fix_windows_console()让 Windows 认 ANSI0.4.6 起可重复调用、无副作用init()老接口功能多别调用多次默认会按环境剥离init(autoresetTrue)自动复位省掉每行结尾的RESET_ALL把这条线记住就够了ANSI 序列是写给终端的不是写给数据的。colorama的工作是让 Windows 也认这套序列而它对输出流的包裹与剥离本质是在「终端需要控制码」与「文件不需要控制码」之间做取舍。最稳妥的做法永远是自己用sys.stdout.isatty()判断一次把颜色当成可选的呈现层——终端上好看文件里干净。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑