V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
bwangel
V2EX  ›  分享创造

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

  •  
  •   bwangel ·
    bwangelme · 2016-11-09 11:53:42 +08:00 · 1859 次点击
    这是一个创建于 2944 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    文章地址

    第 1 条附言  ·  2016-11-10 09:42:56 +08:00
    先把文章移动到草稿里面了,访问地址为

    https://github.com/bwangel23/blog/blob/blog/source/_drafts/python-string-encoding.md

    改好了再重新放出来
    11 条回复    2016-12-11 13:49:22 +08:00
    imn1
        1
    imn1  
       2016-11-09 12:51:02 +08:00
    写程序一律不应该写 gb2312 ,而应该写 gbk 或 cp936 ,两者的字符数量不是一个等级的
    & python 中的 ASCII 编码也不包含高位字节,只是 0-127 的字符,处理包含高位字节应该用 latin-1 编码

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

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

    好吧,今天这么一说,我原来理解确实有问题,我原来一直被 Unicode 的名字迷惑了,以为它叫 Unicode ,所以它就是以 utf8 编码的字符串。
    bwangel
        9
    bwangel  
    OP
       2016-11-10 09:25:50 +08:00
    @bwangel ,漏了第六条了,我去改一下文章,把那个不提倡的方案去掉。
    Sylv
        10
    Sylv  
       2016-11-10 11:33:19 +08:00 via iPhone
    @bwangel
    Unicode 是种字符集标准,而 UTF-8 只是实现它的编码方法之一。
    Unicode 在 Python 内部是用 UCS-2 或 UCS-4 编码表示的。 UTF-8 编码是变长的,用于网络传输等情况时可以节省空间,但运行处理起来相对低效,所以 Python 的 Unicode 内部实现没有用 UTF-8 编码。
    mingyun
        11
    mingyun  
       2016-12-11 13:49:22 +08:00
    s=u'中文'
    obj={'s':s}
    print obj#输出的是对应 Unicode ,怎么输出中文
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2698 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 07:39 · PVG 15:39 · LAX 23:39 · JFK 02:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.