zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    ant 软件包不存在报错
    在 Internet Explorer 中使用 Windows 窗体控件
    智能客户端
    Back to the Future with Smart Clients
    "Automation 服务器不能创建对象" 的解决方案
    Top 10 Reasons for Developers to Create Smart Clients
    Updater Application Block for .NET
    Smart Client Application Model and the .NET Framework 1.1
    Security and Versioning Models in the Windows Forms Engine Help You Create and Deploy Smart Clients
    智能客户端技术总结(二)
  • 原文地址:https://www.cnblogs.com/poloyy/p/15549664.html
Copyright © 2011-2022 走看看