IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python3编码问题全总结 -> 正文阅读

[Python知识库]Python3编码问题全总结


平常主要是写C++,但有时候也需要用到python、shell等脚本来做一些事情,其中最常见的一种应用就是文本处理,而要处理文本不可避免地就要和编码打交道,python3和python2相比在编码方面已经有了很大的进步,但有时候还是会碰到相关问题,以前没怎么特别关注过这块,都是直接用,出了什么编码问题拿报错信息一搜照着改改就完事了,但没有彻底理解很容易走弯路,最近又碰到了一次编码问题,于是最近好好整理学习了下,实际上Python3编码相关的问题也分为好多类,这里就完整地总结一下python3里面最核心的编码相关概念和问题。

一、字符串编码和解码的基本概念

编码这个词搞计算机的人肯定都不陌生,这里讨论的编码特指字符串的编码解码,撇开特定计算机语言,通俗的来说字符串的编码和解码就是字符串和二进制字节串(以下用bytes代替,bytes也是python3中的一种类型)的互相转换,而我们常说的gb2312、utf-8等编码类型则是规定了不同的转换规则。
1.编码:指定编码类型将一个字符串转换成bytes。比如我们将字符串写入文件就需要写入bytes,因此需要编码。
2.解码:指定编码类型将一个bytes转成字符串。

总的来说,我们所说的编码问题本质上都是各种原因造成的编码和解码所用的编码类型不一致所引起的,要保证编码解码不出问题,核心就只有一点:

在对bytes解码的过程中使用和当初它编码时使用的相同编码类型,也就是控制编码解码所用的编码类型一致。

二、Python3各编码解码场景的编码类型一致性保证

只要是涉及到字符串(文本)的场景就避免不了编码解码,具体到python3这个场景里,个人认为可以分为三大类:

  1. 使用bytes.decode和str.encode函数手动操作bytes、字符串对象:这里涉及到的编码类型都可以直接指定。
  2. 执行过程读取脚本文件:Python是解释型的脚本语言,需要在执行的过程中不断地读取代码,在这个过程中就会有解码的问题,比如我们直接定义了一个字符串a=‘字符串’,这里的中文就涉及到编码解码,我们用编辑器写代码保存到文件里的本质就是使用某种编码类型进行编码后将bytes写入到文件,python3解释器在读取相应文件的时候也需要用相同的编码类型进行解码才能保证正确性。
  3. 文本的输入输出:也就是所谓的文本io,Python3里的的io包括三种主要类型: text I/O, binary I/O 和 raw I/O,其中text I/O就需要和编码解码打交道,我们操作的就是文本流,其中就包括我们熟悉的通过open打开文件,以及stdin和stdout的输入输出流。对于文本流,读取本质上就是将从流里获得的的字节码解码成字符串,而写入本质上就是将字符串编码成bytes写到流里。

在具体分析各个场景之前我们先了解下一些python3编码解码相关的默认值,在很多场景如果我们不指定都会使用默认值,因此有必要了解这些默认值在我们执行脚本的环境里是什么:

#python3解释器系统的默认编码
print(sys.getdefaultencoding())

#获取操作系统的locale配置,linux下和shell的locale命令一致。
#python也提供了一些api修改locale,这里不展开,有需要可以自行查阅文档。
print(locale.getdefaultlocale())

下面我们就来看看这几类场景如何保证编码解码所用的编码类型一致。

2.1 字符串和bytes之间转换

python3直接提供了编码解码函数用于字符串到字节码之间的互相转换,如下:
1.编码:str.encode(encoding=‘UTF-8’,errors=‘strict’),返回bytes 对象
2.解码:bytes.decode(encoding=“utf-8”, errors=“strict”),返回字符串

函数很好理解,这里就不多展开了,一句话总结就是指定编码类型对字符串进行编码得到bytes、对bytes进行解码得到字符串,二者均可明确指定编码类型,不太容易出错。

2.2 执行过程读取脚本

这个场景的编码解码涉及到以下两点:

  1. 编辑器在保存源码文件时编码所用的编码类型。
  2. python3解释器在读取源码文件时解码所用的编码类型。

对于编辑器保存时候的编码不用多说,都可以设置。对于后者,默认是使用sys.getdefaultencoding()所指明的编码类型,这个编码类型在linux平台下就是utf-8,如果我们想手动指定,可以通过在脚本开头添加#coding=xxx来指定,有一点需要特别注意,这个仅仅影响解释器读取脚本过程中的解码,很多人会误以为还会影响其他地方的编码设置。

2.3 读写文本文件

python经常用于处理文本,最常见的一种场景就是使用open打开文件从文件输入或者输出到文件,无论是读还是写,我们在打开文件的时候都可以用encoding指定编码类型,比如读取

with open('filename', 'r', encoding='utf-8') as file:
    for line in file:
        do sth

写入

with open('filename', 'w', encoding='utf-8') as file:
    f.write(xxx)
    print("字符串", file=f)

通过指定相同的encoding参数就可以保证一致,如果是读取外部生成的文件,也只需知道其编码便方便地指定。需要注意的是如果我们不指定,会使用和locale.getdefaultlocale()一致的编码。

2.4 文本流输入输出

操作标准的文本输入输出流本质上和操作文件是一样的也是一样的,比如我们常见的读取stdin

for line in sys.stdin:
    do sth

但stdin却不像文件一样可以直接显示指定编码类型,如果碰到了相关的编码问题相对更容易让人疑惑,对于stdin、stdout、stderr,python3有一套默认的编码选择规则,比如python 3.7的官方文档解释如下:
在这里插入图片描述
可以看到,对于linux,默认使用的是locale encoding,如此一来,对于locale encoding不是utf-8的linux环境就很有可能出问题,毕竟现在我们保存文件最常用的编码就是utf-8,比如hadoop streaming场景,如果locale encoding不是utf-8,但是用于cat的文本文件是utf-8的,就会导致使用非utf-8编码类型去解码utf-8编码出来的字节码从而产生问题。

对于此类问题主要有以下几个方法可以解决:

  1. 一个很直接的方法是修改locale encoding,但很多时候执行python3脚本的机器我们并没有权限来做这件事情,而且修改这个影响面太大风险也很大,不是很推荐。
  2. 指定上面文档中提到的PYTHONIOENCODING环境变量,对于这个变量官方解释如下:
    在这里插入图片描述
    也就是在执行脚本前设置好即可指定stdin/stdout/stderr所用的编码类型,如下:
export PYTHONIOENCODING=utf-8
  1. 用TextIOWrapper指定编码来读取sys.stdin内部的raw buffer:
import io
import sys
input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
  1. Python 3.7以及之后的版本也可以在发生实质的read之前使用reconfigure来重新指定IO编码类型:
    在这里插入图片描述
sys.stdin.reconfigure(encoding='utf-8')

三、总结

在碰到python3的编码问题时,首先要做地就是分析具体是哪块的编码解码不一致,进而针对性地修改解决,而不是用笼统的“python3编码问题”一通搜索修改,还是要理解真正的具体原因,这样才能够快速准确地解决问题。

参考:
1.python-3-how-to-specify-stdin-encoding
2.吐血总结,彻底明白 python3 编码原理

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-10-16 19:36:13  更:2021-10-16 19:36:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 23:44:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计