写了一些关于 Python 编码的文字,请大家帮忙指正

2016-11-09 11:53:42 +08:00
 bwangel

Python 编码在现在 Python3 比较普及的情况下应该不是什么头疼的问题了,但感觉搞清楚它还是比较有意义的。我在读了雨痕的《 Python 学习笔记》中的相关内容以后,感觉对于编码的理解比以前加深了一些,所以写出来和大家分享一下,还请大家多多指正。

文章地址

1854 次点击
所在节点    分享创造
11 条回复
imn1
2016-11-09 12:51:02 +08:00
写程序一律不应该写 gb2312 ,而应该写 gbk 或 cp936 ,两者的字符数量不是一个等级的
& python 中的 ASCII 编码也不包含高位字节,只是 0-127 的字符,处理包含高位字节应该用 latin-1 编码

文章中的提及的都不是太难处理的问题,不熟悉编码的人,可能处理数据库读写时的不同编码更棘手

另外,处理手动输入或赋值的字符编码也不难,因为基本都在程序环境内,但从外部读入的就会麻烦了
例如 外部传入字符串"\u2665", python 自然就变成 \\u2665 ,而不是 u'\u2665',处理方式就变了,已经不是编码问题,而是变成字符串转换问题
Sylv
2016-11-09 13:03:31 +08:00
魔幻三行其实一直不是正确的编码问题解决方法,建议别写进文章里,以免误导后人。
Yinz
2016-11-09 13:13:50 +08:00
『 Python3 中正式将这两个概念区分开了, Str 表示的是字符串,拥有编码类型, Bytes 表示的是字节流,没有编码类型。』
这句与我的理解相反? str 是 unicode ,无编码类型; bytes 是字节流,有编码类型,如 utf-8
Sylv
2016-11-09 13:36:49 +08:00
看了文章,感觉你对 Python 的编码理解还是有点乱,特别是文中指定编码和实际编码的部分没说清楚。
dousao
2016-11-09 15:23:29 +08:00
@Sylv 为什么不具体指出问题所在呢?也让其他人学习一下
Sylv
2016-11-09 19:40:11 +08:00
@dousao 呃,之前读了一遍觉得有的地方有点乱,不知该从哪说起。

我又看了遍文章,指出一些我和作者理解不同的地方。

1. 「 Str 表示的是字符串,拥有编码类型, Bytes 表示的是字节流,没有编码类型。」
这句话三楼也指出问题了: Python 3 中的 str 字符串是 Unicode ,存储的是 code points (码点),是没有编码的;而 bytes 相当于 Python 2 的 str ,自身是有编码的。

2. 「当我们创建一个新的字符串的时候,字符串会有一个指定编码,既 Python 认为这个字符串是以什么编码来存储的, Python 默认的指定编码我们可以用 sys.getdefaultencoding()函数来获取到」
sys.getdefaultencoding() 是 Python 的默认编码没错。但是创建新字符串时,字符串的编码和 Python 的默认编码没太大关系。如果字符串是从终端输入的,字符串编码是由终端编码来决定的;如果字符串是写在源码里或者从文件读取的,字符串编码是由文件编码决定的;如果字符串是从网页抓来的,字符串编码是由网页编码决定的。
Python 2 存储的就是原始编码的字符串; Python 3 会将原始字符串用判断出的编码或用户提供的编码来转换为 Unicode 字符串,只有在无法判断出编码时或用户没提供编码时才会用 sys.getdefaultencoding() 的默认编码来转换。

3. 「但是呢,字符串的实际编码并不是说 Python 指定了哪个就是哪个了,这个和系统的默认编码有关」
你这里说的「实际编码」指的是什么?是做什么用的?我没理解。

4. 「而返回的 unicode 对象的默认编码是 utf-8 。」
同上, unicode 对象是没有编码的,你可以用任何支持的编码将 unicode 对象转换为 str 对象,所以不能说 unicode 对象的默认编码是 utf-8 。

5. 「这是因为 Python 写入文件的时候将 Unicode 自动转换成了 Str ,然后这个 Str 的指定编码为 ascii ,但是实际内容却是以 utf-8 来编码的汉字,结果就是抛出编码异常了。」
这句话表述有点问题: Unicode 是没有编码的,所以不能说实际内容是以 utf-8 来编码的汉字。实际上除了 utf-8 编码,你也可以用 gbk 等编码将 unicode 的汉字转换为 str 字符串。而这里因为默认使用的 ascii 编码无法对有汉字的 unicode 字符串进行编码,所以抛出异常了。

6. 「更改 Python 默认的指定编码」
不提倡的解决方法,相关阅读:
https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/
http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes
/t/163786


以上仅是个人理解,不一定都是对的。
bwangel
2016-11-10 09:21:50 +08:00
@imn1 ,受教了,我确实不知道 gb2312 和 gbk 还有这些差别,还有处理从外部处理字符串的,确实这些还没想过。


@Sylv @Yinz


魔幻三行的确实是不应该作为正式解决方案,我之所以叫这个叫做魔幻三行,就是当初第一次遇到这种方案,就是感觉好魔幻,这是个什么鬼。

后面六条我挨个回复一下:

1. 后来一想我感觉这个理解确实有点问题,比如一个 Str 变成 bytes :"中文".encode(),如果这里 encode 没有传入参数的话,这时默认编码会取`sys.getdefaultencoding()`,我把这个编码理解成属于 Str 的了,所以认为 Str 默认带一个编码

2. 3.

这里我的指定编码是 Python 的默认编码,实际编码就是你说的从终端,文件,网页等读取字符串时,这些输入源自己的编码,这些决定了输入字符串实际的编码。

4. 这个和第一点相同,我把`sys,getdefaultencoding()`返回的编码,认为是 Unicode 自带的属性,所以就说 Unicode 有个默认编码。

5. 好吧,这里确实有点问题。这里其实是 Unicode encode 成 str 的时候,使用了 ascii 编码,而 Unicode 中包含汉字,所以无法进行 encode
bwangel
2016-11-10 09:22:55 +08:00
@Yinz @Sylv

好吧,今天这么一说,我原来理解确实有问题,我原来一直被 Unicode 的名字迷惑了,以为它叫 Unicode ,所以它就是以 utf8 编码的字符串。
bwangel
2016-11-10 09:25:50 +08:00
@bwangel ,漏了第六条了,我去改一下文章,把那个不提倡的方案去掉。
Sylv
2016-11-10 11:33:19 +08:00
@bwangel
Unicode 是种字符集标准,而 UTF-8 只是实现它的编码方法之一。
Unicode 在 Python 内部是用 UCS-2 或 UCS-4 编码表示的。 UTF-8 编码是变长的,用于网络传输等情况时可以节省空间,但运行处理起来相对低效,所以 Python 的 Unicode 内部实现没有用 UTF-8 编码。
mingyun
2016-12-11 13:49:22 +08:00
s=u'中文'
obj={'s':s}
print obj#输出的是对应 Unicode ,怎么输出中文

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/319218

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX