Python打印Unicode字符为何偶发UnicodeEncodeError?如何解决?
print('\N{WAVING BLACK FLAG}')
这段代码写法简洁,但在部分机器上能正常打印对应字符,部分机器却会抛出UnicodeEncodeError,错误信息为'ascii' codec can't encode character '\U0001f3f4' in position 0: ordinal not in range(128)。
为什么打印字符有时会触发UnicodeEncodeError?
print函数文档未提及编码相关内容,有没有办法确保字符串打印时不抛出任何异常?
可复现示例
我整理出了稳定复现问题的场景:
主执行脚本代码:
import subprocess import sys subprocess.run([sys.executable, 'test.py'], env=dict())
其中test.py仅包含上述单条print语句。该示例在所有测试机器上均会抛出UnicodeEncodeError,但仅在Python 3.6版本中出现;使用Python 3.7及以上版本则能正常打印字符。
问题原因
标准输出编码的环境依赖:
print函数本质是将字符串写入sys.stdout,而sys.stdout的编码由运行环境决定。当清空环境变量(env=dict())启动子进程时,Python无法获取终端编码信息,在3.6及更早版本中会默认回退到ASCII编码。而\U0001f3f4属于Unicode补充平面字符,超出ASCII的0-127范围,因此触发编码失败的异常。Python 3.7的行为优化:
从Python 3.7开始,官方调整了标准输出的编码逻辑:当无法检测到终端编码时,默认使用UTF-8作为sys.stdout的编码,同时默认启用了编码错误的容错处理,不会直接抛出异常,因此3.7及以上版本可以正常打印该字符。
兼容全版本的解决方案
如果要确保所有Python版本中打印Unicode字符都不抛出异常,可以采用以下几种方式:
- 显式配置标准输出编码:
在代码开头强制设置sys.stdout的编码为UTF-8,并指定错误处理策略:
import sys # Python 3.7及以上版本写法 sys.stdout.reconfigure(encoding='utf-8', errors='replace') # 兼容Python 3.6及更早版本的写法 import codecs sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach(), errors='replace') print('\N{WAVING BLACK FLAG}')
errors='replace'会将无法编码的字符替换为�,避免抛出异常;也可以选择errors='ignore'直接忽略无法编码的字符。
- 通过环境变量强制编码:
启动Python进程时,设置PYTHONIOENCODING=utf-8环境变量,强制标准输出使用UTF-8编码:
import subprocess import sys subprocess.run( [sys.executable, 'test.py'], env={'PYTHONIOENCODING': 'utf-8'} )
这种方式无需修改test.py的代码,适合外部控制进程启动的场景。
- 直接操作字节流输出:
绕过print函数,手动将字符串编码为UTF-8字节流后写入sys.stdout.buffer:
import sys sys.stdout.buffer.write('\N{WAVING BLACK FLAG}'.encode('utf-8') + b'\n')
这种方式不受sys.stdout编码设置的影响,直接输出字节数据,从根源上避免编码异常。
内容的提问来源于stack exchange,提问作者Jeyekomon

