zoukankan      html  css  js  c++  java
  • python中的编码解码

    转至:https://blog.csdn.net/qq_30687757/article/details/88420064?utm_medium=distribute.pc_relevant.none-task-blog-title-14&spm=1001.2101.3001.4242

    Python2的字符串有两种:str 和 unicode,Python3的字符串也有两种:str 和 bytes。Python2 的 str 相当于 Python3 的bytes,而unicode相当于Python3的str。

    Python2里面的str和unicode是可以混用的,在都是英文字母的时候str和unicode没有区别。而Python3 严格区分文本(str)和二进制数据(bytes),文本总是unicode,用str类型,二进制数据则用bytes类型表示,这样严格的限制也让我们对如何使用它们有了清晰的认识,这是很棒的。

    Python2 和 Python3 的区别

    通过以下代码我们认识以下Python2和Python3的字符串混用情况:

    # Python2中:
    
    In [1]: 'a' == u'a'
    Out[1]: True
    
    In [2]: 'a' in u'a'
    Out[2]: True
    
    In [3]: '编程' == u'编程'
    /usr/local/bin/ipython:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
    #!/usr/bin/python
    Out[3]: False
    
    In [4]: '编程' in u'编程'
    ---------------------------------------------------------------------------
    UnicodeDecodeError Traceback (most recent call last)
    <ipython-input-4-7b677a923254> in <module>()
    ----> 1 '编程' in u'编程'
    
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 0: ordinal not in range(128)

    # Python3中: 
    In [1]: 'a' == b'a'
    Out[1]: False
    In [2]: 'a' in b'a'
    ---------------------------------------------------------------------------
    TypeError Traceback (most recent call last) <ipython-input-10-ca907fd8856f> in <module>()
    ----> 1 'a' in b'a'
    TypeError: a bytes-like object is required, not 'str'

    以上代码可以看到,Python2中str和unicode的在都是ascii码时混用没区别,因为unicode的ascii区域的值跟str的ascii是一样的;而对应非ascii区域(比如中文),二者又不一样了,可

    以看到Python2抛出了UnicodeDecodeError的异常,相信这也是很多人处理文本时遇到过的错误;‘编程’在str类型时长度是6,而在unicode时是2。不同字符的不同表现,让Python2的str和unicode显得扑朔迷离。

    在Python3中,严格区分了str和bytes,不同类型之间操作就会抛出TypeError的异常。

    上面用示例阐述了Python2和Python3中字符串的不同,下面主要讲Python3中的字符串。

    str和bytes之间的转换

    一图胜千言:

    在这里插入图片描述

    str和bytes的相互转换

    str.encode(‘encoding’) -> bytes
    bytes.decode(‘encoding’) -> str

    encoding 指的是具体的编码规则的名称,对于中文来说,它可以是这些值: ‘utf-8’, ‘gb2312’, ‘gbk’, ‘big5’ 等等。

    不知道你有没有注意到上图中str矩形要比bytes矩形短,表示同样的内容,str的长度要小于或等于bytes的长度,你可以考虑一下原因(参考Unicode、UTF-8的编码规则)

    下面看看具体代码理解一下str和bytes的相互转换:

    In [16]: a = 'T恤'
    
    In [17]: a
    Out[17]: 'T恤'
    
    In [18]: len(a)
    Out[18]: 2
    
    In [19]: b = a.encode('utf8')
    
    In [20]: b
    Out[20]: b'Txe6x81xa4'
    
    In [21]: a == b
    Out[21]: False
    
    In [22]: c = a.encode('gbk')
    
    In [23]: c
    Out[23]: b'Txd0xf4'
    
    In [24]: b == c
    Out[24]: False
    
    In [25]: a == c
    Out[25]: False
    上面str和bytes之间的转换是针对文本内容的,要是其它二进制内容(比如,图片)时,bytes就不能decode成str了,看以下代码的异常:
    
    In [29]: img = open('str-bytes.jpg', 'rb').read()
    
    In [30]: type(img)
    Out[30]: bytes
    
    In [31]: img.decode('utf8')
    ---------------------------------------------------------------------------
    UnicodeDecodeError Traceback (most recent call last)
    <ipython-input-31-c9e28f45be95> in <module>()
    ----> 1 img.decode('utf8')
    
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
    

      

    因为图片中的二进制数据不符合文本数据的UTF-8编码规则。

    上面获得图片数据时,我们用到了open()来读取文件,文件存储的无非是文本和二进制这两种格式,读写文件时也有分清楚编码:

    In [32]: open('z.txt', 'w').write('T恤')
    Out[32]: 2
    
    In [33]: open('z.txt', 'w').write(img)
    ---------------------------------------------------------------------------
    TypeError Traceback (most recent call last)
    <ipython-input-33-4a88980b3a54> in <module>()
    ----> 1 open('z.txt', 'w').write(img)
    
    TypeError: write() argument must be str, not bytes
    
    In [34]: open('z.txt', 'wb').write(img)
    Out[34]: 12147

    读写二进制数据(如图片)时,要加’rb’参数,b代码binary(二进制)

    读写文本数据时,一般加’b’,open()会自动转换bytes到str。

    总结一下

    Python3里面的str是在内存中对文本数据进行使用的,bytes是对二进制数据使用的。

    str可以encode为bytes,但是bytes不一定可以decode为str。实际上bytes.decode(‘latin1’)可以称为str,也就是说decode使用的编码决定了decode()的成败,同样的,UTF-8编码的bytes字符串用GBK去decode()也会出错。

    bytes一般来自网络读取的数据、从二进制文件(图片等)读取的数据、以二进制模式读取的文本文件(.txt, .html, .py, .cpp等)

    由于接触一段时间后,发现部分有时候指定编码,有时候先编码再解码

    涉及到参数中的encoding=''、decode()解码、encode()编码

    1.requests响应内容关于text以及编码格式

    响应内容

    我们能读取服务器响应的内容。再次以 GitHub 时间线为例:

    >>> import requests
    >>> r = requests.get('https://api.github.com/events')
    >>> r.text
    u'[{"repository":{"open_issues":0,"url":"https://github.com/...

    Requests 会自动解码来自服务器的内容。大多数 unicode 字符集都能被无缝地解码。

    请求发出后,Requests 会基于 HTTP 头部对响应的编码作出有根据的推测。当你访问 r.text 之时,Requests 会使用其推测的文本编码。你可以找出 Requests 使用了什么编码,并且能够使用 r.encoding 属性来改变它:

    >>> r.encoding
    'utf-8'
    >>> r.encoding = 'ISO-8859-1' 

    如果你改变了编码,每当你访问 r.text ,Request 都将会使用 r.encoding 的新值。你可能希望在使用特殊逻辑计算出文本的编码的情况下来修改编码。比如 HTTP 和 XML 自身可以指定编码。这样的话,你应该使用 r.content 来找到编码,然后设置 r.encoding 为相应的编码。这样就能使用正确的编码解析 r.text 了。

    在你需要的情况下,Requests 也可以使用定制的编码。如果你创建了自己的编码,并使用 codecs 模块进行注册,你就可以轻松地使用这个解码器名称作为 r.encoding 的值, 然后由 Requests 来为你处理编码。

    二进制响应内容

    你也能以字节的方式访问请求响应体,对于非文本请求:

    >>> r.content
    b'[{"repository":{"open_issues":0,"url":"https://github.com/... 

    Requests 会自动为你解码 gzip 和 deflate 传输编码的响应数据。

    例如,以请求返回的二进制数据创建一张图片,你可以使用如下代码:

    >>> from PIL import Image
    >>> from io import BytesIO
    
    >>> i = Image.open(BytesIO(r.content))

    JSON 响应内容

    Requests 中也有一个内置的 JSON 解码器,助你处理 JSON 数据:

    >>> import requests
    
    >>> r = requests.get('https://api.github.com/events')
    >>> r.json()
    [{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...

    如果 JSON 解码失败, r.json() 就会抛出一个异常。例如,响应内容是 401 (Unauthorized),尝试访问 r.json() 将会抛出 ValueError: No JSON object could be decoded 异常。

    需要注意的是,成功调用 r.json() 并**不**意味着响应的成功。有的服务器会在失败的响应中包含一个 JSON 对象(比如 HTTP 500 的错误细节)。这种 JSON 会被解码返回。要检查请求是否成功,请使用 r.raise_for_status() 或者检查 r.status_code 是否和你的期望相同。

    原始响应内容

    在罕见的情况下,你可能想获取来自服务器的原始套接字响应,那么你可以访问 r.raw。 如果你确实想这么干,那请你确保在初始请求中设置了 stream=True。具体你可以这么做:

    >>> r = requests.get('https://api.github.com/events', stream=True)
    >>> r.raw
    <requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
    >>> r.raw.read(10)
    'x1fx8bx08x00x00x00x00x00x00x03'

    但一般情况下,你应该以下面的模式将文本流保存到文件:

    with open(filename, 'wb') as fd:
        for chunk in r.iter_content(chunk_size):
            fd.write(chunk)

    使用 Response.iter_content 将会处理大量你直接使用 Response.raw 不得不处理的。 当流下载时,上面是优先推荐的获取内容方式。 Note that chunk_size can be freely adjusted to a number that may better fit your use cases.

  • 相关阅读:
    Python多线程笔记(三),queue模块
    Python多线程笔记(二)
    Python多线程笔记(一)
    Python3对时间模块的操作
    解决 ImportError: No module named 'pip._internal'问题
    Python字符串的操作
    Python 的AES加密与解密
    第十一周学习进度报告
    各组建议
    用户场景分析
  • 原文地址:https://www.cnblogs.com/yescarf/p/13892613.html
Copyright © 2011-2022 走看看