• Effective Python(3) 了解 bytes 与 str 的区别


    Python 有两种类型可以表示字符序列

    • bytes:实例包含的是原始数据,即 8 位的无符号值(通常按照 ASCII 编码标准来显示)
    • str:实例包含的是 Unicode 码点(code point,也叫作代码点),这些码点与人类语言之中的文本字符相对应
    a = b'h\x6511o'
    print(list(a))
    print(a)
    
    a = 'a\\u300 propos'
    print(list(a))
    print(a)
    
    
    # 输出结果
    [104, 101, 49, 49, 111]
    b'he11o'
    
    ['a', '\\', 'u', '3', '0', '0', ' ', 'p', 'r', 'o', 'p', 'o', 's']
    a\u300 propos

    Unicode 数据和二进制数据转换

    • 把  Unicode 数据转换成二进制数据,必须调用 str 的 encode 方法(编码)
    • 把二进制数据转换成 Unicode 数据,必须调用 bytes 的 decode 方法(解码)
    • 调用这些方法时,可以明确指出字符集编码,也可以采用系统默认的方案,通常是 UTF-8

    使用原始的 8 位值与 Unicode 字符串时需要注意的两个问题

    该问题等价于:使用 bytes 和 str 时需要注意的两个问题

    问题一:bytes 和 str 的实例互不兼容

    使用 + 操作符

    # bytes+bytes
    print(b'a' + b'1')
    
    # str+str
    print('b' + '2')
    
    
    # 输出结果
    b'a1'
    b2
    • bytes + bytes,str + str 都是允许的
    • 但 bytes + str 会报错
    # bytes+str
    print('c' + b'2')
    
    
    # 输出结果
    print('c' + b'2')
    TypeError: can only concatenate str (not "bytes") to str

    同类型之间也可以用二元操作符来比较大小

    assert b'c' > b'a'
    
    assert 'c' > 'a'

    但 bytes 和 str 之间用二元操作符也会报错

    assert b'c' > 'a'
    
    
    # 输出结果
        assert b'c' > 'a'
    TypeError: '>' not supported between instances of 'bytes' and 'str'

    判断 bytes 与 str 实例是否相等

    两个类型的实例相比较总会为 False,即使字符完全相同

    # 判断 str、bytes
    print('a' == b'a')
    
    
    # 输出结果
    False

    格式化字符串中的 %s

    两种类型的实例都可以出现在 % 操作符的右侧,用来替换左侧那个格式字符串(format string)里面的 %s

    但是!如果格式字符串是 bytes 类型,那么不能用 str 实例来替换其中的 %s,因为 Python 不知道这个 str 应该按照什么字符集来编码

    # %
    print(b'red %s' % 'blue')
    
    
    # 输出结果
        print(b'red %s' % 'blue')
    TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str'

    但是!反过来却可以,如果格式字符串是 str 类型,则可以用bytes 实例来替换其中的 %s,但结果可能不是预期结果

    # % 
    print('red %s' % b'blue')
    
    
    # 输出结果
    red b'blue'
    • 这样会让系统在 bytes 实例上面调用 __repr__ 方法
    • 调用结果替换格式字符串里的 %s,因此程序会直接输出 b'blue',而不是输出 blue

    问题二:操作文件句柄时需要使用 Unicode 字符串操作

    不能使用原始的 bytes

    向文件写入二进制数据会报错

    # 写入二进制数据
    with open('test.txt', "w+") as f:
        f.write(b"\xf1\xf2")
    
    
    # 输出结果
        f.write(b"\xf1\xf2")
    TypeError: write() argument must be str, not bytes
    • 报错是因为 w 模式必须以文本模式写入
    • 将模式改成 wb 即可正常写入二进制数据
    with open('test.txt', "wb") as f:
        f.write(b"\xf1\xf2")

    读取文件中二进制数据

    with open('test.txt', "r+") as f:
        f.read()
    
    
    # 输出结果
        (result, consumed) = self._buffer_decode(data, self.errors, final)
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte
    •  报错是因为 r 模式必须以文本模式读取
    • 以文本模式操纵文件句柄时,系统会采用默认的文本编码方案处理二进制数据
    • 所以,上面那种写法会让系统通过 bytes.decode 把这份数据解码成 str 字符串,再用 str.encode 把字符串编码成二进制值
    • 然而对于大多数系统来说,默认的文本编码方案是UTF-8,所以系统很可能会把 b'\xf1\xf2\xf3\xf4\xf5' 当成  UTF-8 格式的字符串去解码,于是就会出现上面那样的错误

    将模式改成 rb 即可正常读取二进制数据

    with open('test.txt', "rb") as f:
        print(b"\xf1\xf2" == f.read())
    
    
    # 输出结果
    True

    另一种改法,设置 encoding 参数指定字符串编码

    with open('test.txt', "r", encoding="cp1252") as f:
        print(f.read())
    
    
    # 输出结果
    ñò

    这样也不会有异常了

    重点

    需要注意当前操作系统默认的字符集编码

    https://www.cnblogs.com/poloyy/p/15536156.html

  • 相关阅读:
    flink RECEIVED SIGNAL 15: SIGTERM. Shutting down as requested
    hive 正则
    scala.sys.process
    python多版本管理
    行式存储和列式存储
    Windows Latex 中日文字体设置例
    perl笔记
    wordpress plugins collection
    【转载】Windows 7下使用bcdedit删除多余启动项的命令
    修改MySQL密码
  • 原文地址:https://www.cnblogs.com/poloyy/p/15549664.html
Copyright © 2020-2023  润新知