Python站
  • 说明
  • 源码分析
  • 100 系列
  • python
    • 开发基础
      • 数据类型
      • 字符编码
      • 文本操作
      • 玩转Python100解
    • 函数编程
      • 装饰器
      • 内置函数
        • vars
      • 内置模块
        • enum
        • os
        • argparse
        • importlib
        • shelve
        • collections
        • re
      • 神奇三方
        • setuptools
        • celery
    • 面向对象
      • 面向对象100解(草稿)
    • 网络编程
      • 网络理论知识
      • 网络编程socket
      • socketserver源码泛读
    • 并发编程
      • 并发编程之多进程
        • 子进程基本使用
        • 进程的属性或方法
        • 守护进程
        • 互斥锁
        • 队列
        • 生产者消费者模型
      • 并发编程之多线程
        • 子线程基本使用
        • GIL全局解释器锁
        • 死锁现象与递归锁
        • 信号量事件定时器
        • 线程队列queue
      • 并发编程之进程线程池
      • 并发编程之协程
      • 并发编程之IO模型
        • 阻塞IO
        • 非阻塞IO
        • 多路复用IO
        • 异步IO
        • IO模型比较分析
    • 数据库说
      • mongoengine源码精读
    • 前端开发
    • 后端开发
      • flask源码精读
      • django源码精读
        • 01 软件打包与部署
        • 02 python调试工具 pdb
        • 03 创建一个django项目
    • 爬虫相关
      • Jupyter Notebook
      • urllib
      • urllib3源码泛读
      • 数据解析
      • requests源码精读
        • 初始化说 __init__.py
        • 版本信息 __version__.py
        • 版本兼容 compat.py
        • 经典视图 api.py
        • 逻辑实现 sessions.py
        • 数据存储 models.py
        • 网络传输 adapters.py
        • 异常结构 exceptions.py
        • 交互协定 status_code.py
        • 钩子编程 hooks.py
        • 数据结构 structures.py
        • 辅助输出 utils.py
        • 安全认证 auth&certs.py
    • 编程思想
      • 算法
      • 数据结构
      • 设计模式
        • 简单工厂模式
        • 工厂方法模式
        • 抽象工厂模式
        • 建造者模式
        • 单例模式
        • 适配器模式
        • 桥模式
        • 组合模式
        • 外观模式
        • 代理模式
        • 责任链模式
        • 观察者模式
        • 策略模式
        • 模板方法模式
      • Python技巧100解
      • Effective Python
    • 企业应用
      • DevOps
      • Web服务-Nginx
      • 网站发布
      • 源码管理
        • Git
        • GitHub
        • GitLab
      • Golang
      • Docker
      • Ubuntu
    • 项目实战
    • 就业相关
    • 其他爱好
      • 科技单词100解答
Powered by GitBook
On this page
  • Python3特性预览
  • 字符编码详解
  • Python2中有两种字符串类型str和unicode
  • python3也有两种字符串类型str和bytes
  • 字符编码实践
  1. python
  2. 开发基础

字符编码

Previous数据类型Next文本操作

Last updated 5 years ago

Python3特性预览

文本总是用unicode进行编码,以str类型表示;而二进制数据以bytes类型表示

Python3中最重要的特性将文本(text)和二进制数据做了更清晰的区分

不能以任何隐式方式将str和bytes类型混合使用

  • 不可以将str和bytes类型进行拼接

  • 不能在str中搜索bytes数据(反之亦然)

  • 不能将str作为参数传入需要bytes类型参数的函数(反之亦然)

strings可以被编码(encode)成bytes,bytes也可以解码(decode)成strings

>>> '€20'.encode('utf-8')
b'\xe2\x82\xac20'
>>> b'\xe2\x82\xac20'.decode('utf-8')
'€20'

可以这样理解:

字符串(string)是文本(text)的抽象表示,字符串(string)由字符组成,字符也是抽象的实体且与任何二进制表示无关。当操纵字符串的时候,很多细节是不用了解的,我们可以分割、切片和拼接字符串,在字符串内部进行搜索。但并不在乎内部是如何表示的,也不用在意底层一个字符要花费多少byte。

传入encode和decode的参数是编码方式。编码是一种用二进制数据表示抽象字符的方式。目前有很多种编码。上面给出的utf-8是一种,下面是另一种:

>>> '€20'.encode('iso-8859-15')
b'\xa420' 
>>> b'\xa420'.decode('iso-8859-15')
'€20'

编码是这个转换过程中至关重要的一部分。若不编码,bytes对象b'xa420'只是一堆比特位而已。编码赋予其含义。采用不同的编码,这堆比特位的含义就会大不同:

>>> b'\xa420'.decode('windows-1255') 
'₪20'

字符编码详解

  • 文本编辑器包括Pycharm编写的内容是存在内存中的,断电后丢失;

  • 想要永久保存,需要点击保存按钮 save,把内存中数据刷到硬盘上;

  • 保存save时用二进制的0 1比特存储内存数据,涉及编码,编辑器可指定默认编码;

  • Python解释器先类似编辑器读取read功能,还原硬盘中数据到内存中,涉及编码,和save时一致就行

  • Python解释器执行加载到内存中的数据,识别Python语法,有数据类型的变量,如list,dict,str

  • Python解释器执行到name="Linda"时,会开辟空间存储字符串"Linda",会涉及编码

所以在 保存 - 读取 阶段不乱码的核心法则是:字符保存时按照什么标准编码,读取时就按照什么标准解码

# 文件test.py 以gbk格式保存,内容为:
country = '中国'

python2 test.py
python3 test.py

都会报错(因为python2默认ascii,python3默认utf-8)

除非在文件开头指定 # coding: gbk

在解释器执行阶段,数据已经正常读取到内存中(统一unicode编码),然后执行,执行过程中会开辟新的空间,如 x = "Linda"

内存的编码是用unicode,不代表内存全都是unicode

在程序执行之前,内存中确实都是unicode,
比如从文件中读取了一行x = "Linda",其中的x,= ,"",地位都一样,都是普通字符而已,都是以unicode的格式存放于内存中的

但是程序在执行过程中,会申请内存(与程序代码所存在的内存是俩个空间)用来存放python的数据类型的值,
而python的字符串类型又涉及到了字符的概念

比如x = "Linda", 会被python解释器识别为字符串,会申请内存空间来存放字符串类型的值,
至于该字符串类型的值被识别成何种编码存放,这就与python解释器的有关了,而python2与python3的字符串类型又有所不同 

Python2中有两种字符串类型str和unicode

str类型

当python解释器执行到产生字符串的代码时(如x='上'),会申请新的内存地址,然后将'上'编码成文件开头指定的编码格式,想看x在内存中的真实格式,可以将其放入列表中再打印,而不要直接打印,直接print会自动转码

# -*- coding: gbk -*-
x = '上'
y = '下'
print([x, y])             # ['\xc9\xcf', '\xcf\xc2']
print(type(x), type(y))   # (<type 'str'>, <type 'str'>)
# 16进制 \x, gbm中文2个字节,16位比特(0或1),4个16进制字符(0-f)

print(['上'.decode('gbk'), '下'.decode('gbk')])    # [u'\u4e0a', u'\u4e0b']

unicode类型

当python解释器执行到产生字符串的代码时(如x=u'上'),会申请新的内存地址,然后将'上'已unicode的格式存放到新的内存空间中,所以x只能encode,不能decode

# -*- coding: gbk -*-
x = u'上'        # 等同于 x = '上'.decode('gbk')
y = u'下'        # 等同于 x = '下'.decode('gbk')
print([x, y])    # [u'\u4e0a', u'\u4e0b']
print(type(x), type(y))     # (<type 'unicode'>, <type 'unicode'>)

打印到终端

# -*- coding: gbk -*-
x = '上'    # '\xc9\xcf'
print(x)    #  这一步将x指向的那块新的内存空间(非代码所在的内存空间)中的内存,打印到终端
# 按理说应该打印 '\xc9\xcf',但不熟悉的程序员立马懵逼,所以龟叔自作主张在print时,
# 使用终端的编码格式,将内存中'\xc9\xcf'转换成字符显示,此时就要求终端编码格式必须为gbk,否则无法显示

# x = u'上'  # u'\u4e0a'
# unicode可以转换成任意编码,pycharm的utf-8还是windows的gbk都不会报错

python刚诞生之际,unicode编码还没有统一,所以str是bytes类型,python3直接str为unicode

python3也有两种字符串类型str和bytes

# -*- coding: gbk -*-
x = '上'          # 当程序执行时,无需加u,'上'也会被以unicode形式保存新的内存空间中
print(type(x))   #  <class 'str'>

# x可以直接encode成任意编码格式
print(x.encode('gbk'))          # b'\xc9\xcf'
print(type(x.encode('gbk')))    # <class 'bytes'>

看到python3中x.encode('gbk')的结果'\xc9\xcf'正是python2中的str类型的值, 而在python3是bytes类型,

在python2中则是str类型,python2中的str类型就是python3的bytes类型

字符编码实践

# coding:utf-8
import six
def to_unicode(s, encoding='utf-8', errors='strict'):
    if six.PY2:
        return s if isinstance(s, unicode)\
               else s.decode(encoding, errors=errors)
    else:
        return s if isinstance(s, six.string_types)\
               else s.decode(encoding, errors=errors)

def to_byte(s, encoding='utf-8', errors='strict'):
    if six.PY2:
        return s.encode(encoding, errors=errors)\
               if isinstance(s, unicode) else s
    else:
        return s.encode(encoding, errors=errors)\
               if isinstance(s, six.string_types) else s

附:

附:

原文链接
原文链接