目录

正文

  在开发过程中,我们经常需要打印一些变量的值,便于调试。这个时候就会发现如果在dict list这些容器中,如果包含中文字符,不管是str类型,还是unicode类型,都打印不出来。如下:

>>> print {'name': '张三'}
{'name': '\xd5\xc5\xc8\xfd'}
>>> print {'name': u'张三'}
{'name': u'\u5f20\u4e09'}

  当然,作为凡人的我是在无法脑补这些十六进制的意思,每次转移一下也很麻烦,有没有办法一劳永逸呢。google了一把,发现还是有很多姿势的。

  注意:本文实验主要基于win7,Python2.7,运行环境如下

>>> import sys,locale
>>> sys.getdefaultencoding()
'ascii'
>>> locale.getdefaultlocale()
('zh_CN', 'cp936')
>>> sys.stdin.encoding
'cp936'
>>> sys.stdout.encoding
'cp936'

  本文地址:http://www.cnblogs.com/xybaby/p/7854126.html

str类型的中文

  首先让我们分析一下为什么无法包含中文的container(dict list tuple)

>>> data = {'严': 1, 2: ['如'], 3:'玉'}

>>> data
{2: ['\xc8\xe7'], 3: '\xd3\xf1', '\xd1\xcf': 1}
>>> print data
{2: ['\xc8\xe7'], 3: '\xd3\xf1', '\xd1\xcf': 1}
>>> print data[3]

  上面data在key value中包含中文,而且也有嵌套的list,后文都使用这个data

  可以看到不管是直接输出data(调用dict.__repr__),还是print data(调用dict.__str__),都无法输出中文,而是像str.__repr__的结果。即调用容器的__str__时,事实上调用的是容器元素的__repr__方法,这个很好验证:

>>> class OBJ(object):
... def __str__(self):
...    return 'OBJ str'
... def __repr__(self):
...    return 'OBJ repr'
...
>>> lst = [OBJ()]
>>> print lst
[OBJ repr]
>>>

  OBJ这个自定义的类,__str__ __repr__的方法实现不一样,当作为container(list)的元素时,明显调用的是OBJ.__repr__

  在stackoverflow上的一个问题print-a-list-that-contains-chinese-characters-in-python给出了答案

When you print foo, what gets printed out is str(foo).
However, if foo is a list, str(foo) uses repr(bar) for each element bar, not str(bar).

  当然,这个问题早就被人发现了,在PEP3140 str(container) should call str(item), not repr(item),在这个提议中,就建议在打印容器的时候,使用__str__而不是__repr__。但是被Guido(Python之父)无情的拒绝了,原因是:

Guido said this would cause too much disturbance too close to beta

  虽然提议被reject了,但是需求还是照样存在的啊,于是有了各种解决办法

第一种姿势:逐个打印

  直接print容器中的元素

>>> lst = ['张三', '李四']
>>> print '[' + ', '.join(["asdf", "中文"]) + ']'
[asdf, 中文]
>>> for k, v in {'name': '张三'}.items():
... print k, v
...
name 张三

  对于简单的容器对象,还是很方便的,但是对于嵌套的容器对象,比如上面data的例子,就很麻烦了

第二种姿势: json dumps

  这个方法在网上推荐得较多

>>> import json
>>> dumped_data = json.dumps(data, encoding = 'gbk', ensure_ascii=False)
>>> print dumped_data
{"2": ["如"], "3": "玉", "严": 1}

  可以看到,虽然打印出了中文,但是2 3都被加上了引号,感觉怪怪的

  需要注意的是上面的两个参数(encoing ensure_ascii), 这两个参数都有默认参数(encoding = 'utf-8', ensure_ascii=True),跟我们这里使用的都不一样。

>>> dumped_data = json.dumps(data)
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Python27.9\lib\json\__init__.py", line 243, in dumps
    return _default_encoder.encode(obj)
  File "D:\Python27.9\lib\json\encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "D:\Python27.9\lib\json\encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc8 in position 0: invalid continuation byte

  当然,为什么这里爆出了UnicodeDecodeError,可以参考这篇文章《不想再被鄙视?那就看进来! 一文搞懂Python2字符编码

  ensure_ascii参数也很关键

>>> dumped_data = json.dumps(data, encoding = 'gbk')
>>> print dumped_data
{"2": ["\u5982"], "3": "\u7389", "\u4e25": 1}

  python document是有描述的;

If ensure_ascii is True (the default), all non-ASCII characters in the output are escaped with \uXXXX sequences, and the result is a str instance consisting of ASCII characters only.

第三种姿势: repr string_escape

>>> decoded_data = repr(data).decode('string_escape')
>>> print decoded_data
{2: ['如'], 3: '玉', '严': 1}

  既然repr的输出是十六进制的str,那么就可以使用string_escape进行转换,具体也可以参见上文

第四种姿势:PEP3140

  虽然PEP3140被reject了,但我们还是可以利用其思想吧,那就是强制调用str.__str__而不是str.__repr__

 1 class ForceStr(str):
2 def __repr__(self):
3 return super(ForceStr, self).__str__()
4
5 def switch_container( data ):
6 ret = None
7 if isinstance(data, str):
8 ret = ForceStr(data)
9 elif isinstance(data, list) or isinstance(data, tuple):
10 ret = [switch_container(var) for var in data]
11 elif isinstance(data, dict):
12 ret = dict((switch_container(k), switch_container(v)) for k, v in data.iteritems())
13 else:
14 ret = data
15 return ret

>>> switched_data = switch_container(data)
>>> print switched_data
{2: [如], 3: 玉, 严: 1}
>>> switched_data
{2: [如], 3: 玉, 严: 1}

  ForceStr继承自str,然后ForceStr.__repr__调用str.__str__。然后递归将容器里面的str类型的元素替换成ForceStr。可以看到,能够顺序打印出中文,格式也没有问题

unicode类型的中文

  基本姿势于上一章节是一样的,下面直接给出答案

  同上第二种姿势

>>> udata = {u'严': 1, 2: [u'如'], 3:u'玉'}
>>> print json.dumps(udata, encoding = 'gbk', ensure_ascii=False)
{"2": ["如"], "3": "玉", "严": 1}

  同上第三种姿势

>>> print repr(udata).decode('unicode_escape')
{2: [u'如'], 3: u'玉', u'严': 1}
>>>

  同上第四种姿势

 1 def switch_container( data ):
2 ret = None
3 if isinstance(data, unicode):
4 ret = ForceStr(data.encode(sys.stdout.encoding))
5 elif isinstance(data, list) or isinstance(data, tuple):
6 ret = [switch_container(var) for var in data]
7 elif isinstance(data, dict):
8 ret = dict((switch_container(k), switch_container(v)) for k, v in data.iteritems())
9 else:
10 ret = data
11 return ret

>>>
>>> print switch_container(udata)
{2: [如], 3: 玉, 严: 1}

当str与unicode中文并存时

同上第二种姿势

>>> data[4] = u'啊'
>>> print json.dumps(data, encoding = 'gbk', ensure_ascii=False)
{"2": ["如"], "3": "玉", "4": "啊", "严": 1}

同上第三种姿势

>>> print repr(data).decode('string_escape')
{2: ['如'], 3: '玉', 4: u'\u554a', '严': 1}

  呃,unicode中文打印不出来

>>> print repr(data).decode('unicode_escape')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'gbk' codec can't encode character u'\xc8' in position 6: illegal multibyte sequence
>>>

  擦,也许有正确的姿势,不过我没有试出来

  同上第四种姿势

 1 def switch_container( data ):
2 ret = None
3 if isinstance(data, str):
4 ret = ForceStr(data)
5 elif isinstance(data, unicode):
6 ret = ForceStr(data.encode(sys.stdout.encoding))
7 elif isinstance(data, list) or isinstance(data, tuple):
8 ret = [switch_container(var) for var in data]
9 elif isinstance(data, dict):
10 ret = dict((switch_container(k), switch_container(v)) for k, v in data.iteritems())
11 else:
12 ret = data
13 return ret

>>> print switch_container(data)
{2: [如], 3: 玉, 4: 啊, 严: 1}

总结

  json.dumps版本还算可以,能够处理str中文,unicode中文, str与unicode中文并存三种情况,不过显示结果与真实有点差异

  string_escape(unicode_escape)只使用只有str(unicode)中文的情况,使用较为受限

  自己实现的switch_container版本,能够友好支持str中文,unicode中文,str与unicode中文并存三种情况

  str与unicode并存真是一件蛋疼的事情!

python2.7 关于打印中文的各种方法的更多相关文章

  1. Python基础教程(015)--Python2默认不支持中文

    前言 Python2默认不支持中文 内容 市场上有Python2,和Python3, Python2的解释器不支持中文. 用Python3来运行文件. 错误信息 SyntaxError:Non-ASC ...

  2. python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色)

    python cmd 窗口 中文乱码 解决方法 (附:打印不同颜色) 前言 在 python 开发中,有时候想通过cmd窗口来和用户交互,比如显示信息之类的,会比自己创建 GUI 来的方便,但是随之而 ...

  3. 【原创】python中文编码问题深入分析(二):print打印中文异常及显示乱码问题分析与解决

    在学习python以及在使用python进行项目开发的过程中,经常会使用print语句打印一些调试信息,这些调试信息中往往会包含中文,如果你使用python版本是python2.7,或许你也会遇到和我 ...

  4. ZPL打印中文信息

    博客来源:http://www.cnblogs.com/Geton/p/3595312.html 相信各位在实际的项目中,需要开发打条码模块的也会有不少,很多同行肯定也一直觉得斑马打印机很不错,但是Z ...

  5. [置顶] 如何vs在cocos2dx项目中打印中文

    一开始不是很理解,查了半天资料,终于找到解决方法,但是有部分中文还是不能打印出来,如 会出现部分的中文, 一开始都是问号的解决方法是 点击高级保存选项 设置成Unicode(UTF-8无签名) 这样就 ...

  6. python中打印中文

    python中打印中文 在python 2.x版本中,默认是ASCII编码方式,在有业务需要输入中文时,就会出现乱码的情况.解决这种问题的一个方式就是设置py文件的编码方式.实现方式如下: 在py文件 ...

  7. sublime text3 中 python3编译出现中文乱码解决方法

    转 https://blog.csdn.net/Bin_bin_bingo/article/details/80531582 一.乱码现象 利用sublime自带编译快捷方式ctrl+B会出现中文乱码 ...

  8. javaWeb项目springMVC框架下利用ITextpdf 工具打印PDF文件的方法(打印表单、插入图片)

    方法一:打印PDF表单以及在PDF中加入图片 需要的资料: jar包:iTextAsian.jar ,itext-2.1.7.jar: 源码: public static void main(Stri ...

  9. SecureCRT——设置打印中文字符

    1. 设置方法 使用SecureCRT打印由STM32发送的中文字符提示信息,显示乱码.在网上找了一些链接,再加上自己摸索,终于出了能够让SecureCRT打印中文的方法. 设置以下几个地方即可. 1 ...

随机推荐

  1. 20155227 2016-2017-2 《Java程序设计》第七周学习总结

    20155227 2016-2017-2 <Java程序设计>第七周学习总结 教材学习内容总结 认识时间与日期 时间的度量 世界时:在1972年引入UTC之前,GMT与UT是相同的. 国际 ...

  2. 【转】线程间操作无效: 从不是创建控件“textBox2” 的线程访问它。

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  3. 最长上升子序列O(nlogn) 要强的T^T(2358)

    题目来源:http://www.fjutacm.com/Problem.jsp?pid=2358 要强的T^T TimeLimit:1000MS  MemoryLimit:65536K 64-bit ...

  4. 查看linux系统的信息

    #!/bin/sh ################################################## #function:get host's information #Autho ...

  5. mysql使用模板解决旧数据处理,默认初始化数据的通用方法!

    一 业务介绍 先来看看我这得大致业务需求,这次业务比较简单: 即从现在开始,每次new一个爷爷都需要默认初始化给这个爷爷三个儿子(子表,爷爷id去关联),并在初始化每个儿子的同时再给每个儿子初始化若干 ...

  6. 虚拟环境pipenv的使用

    安装虚拟环境 安装python3.6 python -m site --user-base 找到 用户基础目录 指定python版本的方式 pipenv --python 3.8 安装 用户范围内安装 ...

  7. 电脑蓝屏提示unexpected store exception的解决方法

    在我们使用电脑的过程中常常会遇到许多问题,对于许多不熟悉电脑的用户常常摸不着头脑,而部分用户在使用电脑时,电脑常常出现蓝屏的情况,并提示你的电脑遇到问题需要重新启动,与此同时,其报告错误代码为“une ...

  8. align="absmiddle" 的意义

    align=absmiddle表示图像的中间与同一行中最大元素的中间对齐 AbsBottom 图像的下边缘与同一行中最大元素的下边缘对齐. AbsMiddle   图像的中间与同一行中最大元素的中间对 ...

  9. 制作macOS10.12系列的系统镜像文件

    制作macOS10.12系列的系统镜像文件步骤,过程也比较简单,十来个命令.以10.12.6为例,首先,在苹果商店下载系统安装包APP,或者网上下载后把安装APP复制到  应用程序  文件夹. 然后打 ...

  10. java基础42 File类的构造函数及其方法

    本文知识点(目录): 1.IO流(Input Output)    2.IO流技术的运用场景    3.File类的构造函数(方法)    4.File类的一些常用方法    5.实例(解析File类 ...