unicode字符_了解Bytes、Str、Unicode三者之间的关系

(文章写的有点乱,凑合看吧)

在Python 3中有两种表示字符串的方式:bytes和str。bytes的实例包含原始的8位值(raw 8-bit values);str实例包含Unicode字符。

Python 2中也有两种表示字符串的方式:str和unicode。与Python 3对比,Python 2中str实例包含原始的8位值,unicode包含Unicode字符。

有很多种方式能够将Unicode字符表示为二进制数据(binary data,raw 8-bit values)。最常用的一种编码格式是UTF-8。需要注意的是,Python 3中的str实例以及Python 2中的unicode实例都没有相关的二进制编码格式。要想使Unicode字符转换成二进制数据必须使用encode方法。要想使二进制数据转换成Unicode字符必须使用decode方法。

d86709e646a76dd78e70ce369ec4da9c.png

Python 3代码示例:

e892f4a7f7a0b9b0f36376f859207793.png

当你在编写Python程序时,最好在远离接口的地方进行decode、encode操作。代码的核心应该使用Unicode字符类型(Python 3中使用str,Python 2中使用unicode),并且不应当对任何字符串进行encode操作。这样做的好处就是,当你需要严格控制你的输出文本的编码格式时,你的代码可以很容易的转换成其它字符编码格式,例如latin-1、Shift JIS、 Big5等。Python针对字符类型的分类引出了两种问题:

  • 按照8位原始值的形式操作UTF-8字符串或者其它编码格式字符串;
  • 操作Unicode字符。

此时你需要一些帮助方法来帮助你修改方法的输入参数,使这些参数的编码格式符合你的要求。

在Python 3中你需要一个方法接收str或bytes,返回str:

febbc45462f8fa0f12cc4a3774a3cc6e.png

同时需要另一个方法接收str或者bytes返回bytes:

d7097fd53cf14e76dd4c6e58184b080d.png

在Python 2中你需要一个方法,这个方法接收str或unicode,返回unicode:

def to_unicode(unicode_or_str): if isinstance(unicode_or_str, str): value = unicode_or_str.decode('utf-8') else: value = unicode_or_str return value # Instance of unicode

同时需要另一个方法用于接收str或者unicode,返回str:

def to_str(unicode_or_str): if isinstance(unicode_or_str, unicode): value = unicode_or_str.encode('utf-8') else: value = unicode_or_str return value # Instance of str

在Python中处理原始8位值和Unicode字符时有两个大问题。

第一个问题是在Python 2中,如果一个字符串只包含7位的ACSII字符时,str和unicode实例看起来是一样的。

  • 可以使用+链接两个str和unicode对象;
  • 可以使用等于、不等于操作符比较两个str和unicode对象;
  • 可以使用unicode实例作为格式化字符串,例如"%s"。

上面的行为意味着不论一个方法期望接收的是str还是unicode对象,你都可以随意传递这两个中的一个。在Python 3中,bytes和str从来都不是一回事,甚至空对象也不一样,所以在传递字符序列时一定要注意所传递的数据类型。

另一个问题是,在Python 3中文件处理方法返回的对象(open方法返回的对象)默认是使用UTF-8编码的。在Python 2中文件操作默认返回二进制编码(binary encoding)。这会导致一些奇怪的问题,尤其是那些习惯于Python 2的程序员。

例如,想要向文件中写入一些随机的二进制数据,Python 2就可以实现,但是Python 3就会出现异常。

with open('/tmp/random.bin', 'w') as f: f.write(os.urandom(10))>>>TypeError: must be str, not bytes

出现这个错误的原因是因为在Python 3中open方法增加了一个encoding参数。这个参数的默认值是UTF-8,这使得open方法返回对象的read和write方法都是使用包含unicode字符的str对象而不是使用bytes数据。

要想使read、write工作正常,你必须指定文件是按照二进制写(wb)模式打开的,而不是简单的使用写(w)模式。修改上面代码,使用"wb"默认就可以同时在Python 2和Python 3中正常执行了:

with open('/tmp/random.bin', 'wb') as f: f.write(os.urandom(10))

同样的问题也会出现在read方法中,解决方法是一样的,修改文件打开模式,使用"rb"。

总结:

  • 在Python 3中,bytes包含8位序列值,str包含unicode字符序列。 bytes和str实例不能一起使用(比如, > 或 +);
  • 在Python 2中,str包含8位序列值,unicode包含unicode字符序列。当str仅包含7位ACSII字符时,str和unicode实例可以一起使用;
  • 使用heler方法来保证输入的字符串是你希望的类型 (如:8位值序列、UTF-8字符串、Unicode字符串等);
  • 如果想从文件读或者写二进制数据,一定要使用二进制形式打开文件(“rb”或者"wb")。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值