Python 3 中字符串和 bytes 的区别
在Python中字符串和unicode真是傻傻分不清楚,在没搞懂两个区别时,你会发现程序报的错怎么改都是再报错,让你烦躁。
学习Python的时候,又重温了这部分内容,写了这个学习笔记。

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'T\xe6\x81\xa4' In [21]: a == b
Out[21]: False In [22]: c = a.encode('gbk') In [23]: c
Out[23]: b'T\xd0\xf4' 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。
文章首发于我的技术博客猿人学的Python基础教程
Python 3 中字符串和 bytes 的区别的更多相关文章
- Python 3中字符串可以被改变吗?
Python 3中字符串可以被改变吗? 字符串有改变这个方法的:replace,比如: a = 'lkjhgfdsa' a.replace(') '123kjhgfdsa' #返回结果 从上面这个例子 ...
- 【转】python类中super()和__init__()的区别
[转]python类中super()和__init__()的区别 单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(se ...
- python redis中blpop和lpop的区别
python redis 中blpop返回的是元组对象,因此返回的时候注意 lpop返回的是对象
- golang中字符串、bytes类型切片、16进制字符串之间的转换
func main() { // 字符串转bytes类型 name := "马亚南" fmt.Println(name) // 马亚南 bName := []byte(name) ...
- python列表与字符串、元组的区别以及列表引用的方式
一.字符串 字符串也可以用下标取值.切片.for循环.len()取长度以及 in 和 not in 来进行操作. 但字符串是不可变的,不能被更改.只能构造一个“新的”字符串来存取你想要修改后的数据. ...
- python 列表中字符串排序故事一则
a = ["bca","cab","abc"] 有时候需要对列表排序 如果是对列表中整个元素 直接用sort()排序 如果想按元素的某一段排 ...
- python类中super()和__init__()的区别
class Base(object): def __init__(self): print 'Base create' class childB(Base): def __init__(sel ...
- Python 3中bytes/string的区别
原文:http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 python 3中最重要的新特性可能就是将文 ...
- 学习python,第四篇:Python 3中bytes/string的区别
原文:http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 python 3中最重要的新特性可能就是将文 ...
随机推荐
- linux Centos系统安装Pycharm并创建软链接
一.环境:Linux|CentOS系统 二.目的:在Linux环境下使用Pycharm(版本2018.3.4) 三.声明:不可用于商业,仅用于交流使用! 1.下载Pycharm压缩包: cd ~ wg ...
- Unreal Engine* 4/英特尔® VTune™ Amplifier 使用指南
借助英特尔 VTune Amplifier,可以通过单一易用的分析界面获得先进的分析功能.UE4 和英特尔 VTune Amplifier 相互配合,支持调查代码并进行分析,从而在多个内核上顺畅运行. ...
- oracle+mybatis批量插入踩坑记
最近在项目中需要使用oracle+mybatis批量插入数据,因为自增主键,遇到问题,现记录如下: 一.常用的两种sql写法报错 1.insert ... values ... <insert ...
- 深入理解C语言-二级指针三种内存模型
二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {&quo ...
- python 指定文件夹下所有文件(包括子目录下的文件)拷贝到目标文件夹下
#!/usr/bin/env python3 # -*- coding:utf8 -*- # @TIME :2018/9/17 9:02 # @Author:dazhan # @File :copyf ...
- vue $refs获取dom元素
1.今天做vue项目有个获取dom节点,主要目的是获取节点让滚动到顶部 首先在滑动容器去添加ref <div class="contentScroll" ref=" ...
- 自然语言处理工具python调用hanlp的方法步骤
Python调用hanlp的方法此前有分享过,本篇文章分享自“逍遥自在017”的博客,个别处有修改,阅读时请注意! 1.首先安装jpype 首先各种坑,jdk和python 版本位数必须一致,我用的是 ...
- Servlet中获取POST请求的参数
在servlet.filter等中获取POST请求的参数 form表单形式提交post方式,可以直接从 request 的 getParameterMap 方法中获取到参数 JSON形式提交post方 ...
- C++类的对象和类的指针的区别
#include <iostream> #include <string> using namespace std; class Student { public: stati ...
- navicat 使用 pymysql模块
新健库 ,新增字段+类型+约束 设计表:外键(自增) 新建查询 建立表模型 /* 数据导入: Navicat Premium Data Transfer Source Server : localho ...