Python 教学 021

一、Python 原码、反码、补码

按32位计算,原码是数的二进制表示,内部存储与运算是补码,转换用的是反码。

+1 的原码:0000 0000 0000 0001
-1 的原码:1000 0000 0000 0001
-1 的反码:1111 1111 1111 1110
-1 的补码:1111 1111 1111 1111

重新计算 -1+1 结果:(用的都是补码)

1111 1111 1111 1111

0000 0000 0000 0001

-----------------------

1 0000 0000 0000 0000

正数:原码 = 反码 = 补码
负数:反码 = 符号位不变,其他位取反
补码 <=> 反码+1<=>原码    (反码+1=-1反码)

-1的补码:1111 1111 1111 1111
    取反:1000 0000 0000 0000
-1的原码:1000 0000 0000 0001

补码用来做数据的存储运算,可以实现计算机底层的减法操作默认计算机只会做加法,例:5+(-3) => 5 – 3,乘法除法是通过左移和右移 << >> 来实现。

python 中的按位取反运算

按位取反运算符:~  #是对补码取反操作

运算结果:~x=-(x+1)

例如:~9为-10

原码:0000 1001    9

~:1111 0110    246

1、~9 的计算步骤:

原码:0000 0000 0000 1001

补码:0000 0000 0000 1001

按位取反:1111 1111 1111 0110

要知道它所表达的数是多少,需要转换为原码

补码:1111 1111 1111 0110

反码:1000 0000 0000 1001

原码:1000 0000 0000 1010

符号位为1是负数,即-10

2、~-9 的计算步骤:

原码:1000 0000 0000 1001

补码:1111 1111 1111 0111

按位取反:0000 0000 0000 1000

原码:正数的补码和原码相同,仍为:0 1000,即8

注意:按位取反是针对补码的操作

-61:11 1101 32+16+8+4+0+1

1000 0000 0011 1101  注:是16位,32位一样理解。

二、Python 中的字符编码

1、字符与字节

字符与人类更为接近,而字节则与计算机(机器)更为接近。

Unicode 才是真正的字符串,而 ASCIIUTF-8GBK 等编码格式表示的都是字节码。

字符串是由字符构成,字符在计算机硬件中通过二进制形式存储,这种二进制形式就是字节码。unicode 就是 “与存储无关的表示”,是一种字符集,而 ASCII、UTF-8、GBK 等就是字符串对应的“二进制表示”。

Unicode 解决了人类识别计算机语言的兼容性和可用性问题,是一种字符串(只是一种字符集,而没有编码格式),而ASCIIUTF-8GBK 等是解决字符信息(Unicode)如何在计算机内部存储和传输的,是二进制形式的字节码。

Python 教学 021

Unicode 是解决如何向人类展现可被识别的字符问题,而 UTF-8 是解决如何将人类可识别的字符转换为可被机器识别的字节码问题。

Python3 所有的字符串都是Unicode字符串

Python3 中解释器默认的字符编码是 UTF-8

>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

也可在文件头增加字符编码的显式声明:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
s='你好,世界!'
print(s)

程序在执行时解释器会通过指定的字符编码 UTF-8 来对保存的字节码进行解码。

2、编码

ASCII 编码是1个字节,而 Unicode 编码通常是2个字节。(如果要用到非常偏僻的字符,就需要4个字节) UTF-8 编码把一个 Unicode 字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。

字符

ASCII

Unicode

UTF-8

A

01000001

00000000 01000001

01000001

x

01001110 00101101

11100100 10111000 10101101

3、编码格式与 Unicode

字符串在系统内部存储为 0x0--0x10FFFF 范围内的码位序列。

一旦字符串对象要在 CPU 和内存以外使用,字节的大小、顺序和字节数组的存储方式就成为一个关键问题。 如同使用其他编解码器一样,将字符串序列化为字节序列被称为 编码,而从字节序列重建字符串被称为 解码。 存在许多不同的文本序列化编解码器,它们被统称为 文本编码。

其中一种编码格式能够对所有的 Unicode 字符进行编码:UTF-8。 UTF-8 是一种 8 位编码,这意味着在 UTF-8 中没有字节顺序问题。 UTF-8 字节序列中的每个字节由两部分组成:标志位(最重要的位)和内容位。 标志位是由零至四个值为 1 的二进制位加一个值为 0 的二进制位构成的序列。 Unicode 字符会按以下形式进行编码(其中 x 为内容位,当拼接为一体时将给出对应的 Unicode 字符):

范围

编码

U-00000000 ... U-0000007F

0xxxxxxx                 0x7f=127

U-00000080 ... U-000007FF

110xxxxx 10xxxxxx        0x7ff=2047

U-00000800 ... U-0000FFFF

1110xxxx 10xxxxxx 10xxxxxx   65535

U-00010000 ... U-0010FFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

chr(i)

返回 Unicode 码位为整数 i 的字符的字符串格式。例如,chr(97) 返回字符串 'a',chr(8364) 返回字符串 '€'。这是 ord() 的逆函数。

实参的合法范围是 0 到 1,114,111(16 进制表示是 0x10FFFF)。如果 i 超过这个范围,会触发 ValueError异常。

ord(c)

对表示单个 Unicode 字符的字符串,返回代表它 Unicode 码点的整数。例如 ord('a') 返回整数 97, ord('中') 返回 20013 。

字符串这种序列与其它序列(如列表、元组)的不同之处在于,它的“元素”限定了只能是 Unicode 码点。Unicode 码点是什么呢?简单理解,就是用 Unicode 编码的字符。那字符是什么呢?字符是人类书写系统的各类符号,例如阿拉伯数字、拉丁字母、中文、日文、藏文、标点符号、控制符号(换行符、制表符等)、其它特殊符号(@#¥%$*等等)。那 Unicode 编码又是什么呢?Unicode  别名是万国码、国际码,它是一种适用性最广的、将书写字符编码为计算机数字的标准。

总所周知,在最底层的计算机硬件世界里,只有 0 和 1。那么,怎么用这个二进制数字,来表示人类的文化性的字符呢?这些字符数量庞大,而且还在日益增长与变化,什么样的编码方案才是最靠谱的呢?

历史上,人类创造了多种多样的字符编码标准,例如 ASCII(1963年)编码,以西欧语言的字符为主,它的缺点是只能编码128个字符;例如 GB2312(1981年),这是中国推出的编码标准,在兼容 ASCII 标准的基础上,还加入了对日文、俄文等字符的编码,但缺点仍是编码范围有限,无法表示古汉语、繁体字及更多书写系统的字符。

Unicode 编码标准于1991年推出,至今迭代到了第11版,已经能够编码146个书写系统的130000个字符,可谓是无所不包,真不愧是“国际码”。Unicode 编码其实是一个二进制字符集,它建立了从书写字符映射成唯一的数字字符的关系,但是,由于各系统平台对字符的理解差异,以及出于节省空间的考虑,Unicode 编码还需要再做一次转换,转换后的新的二进制数字才能作为实际存储及网络传输时的编码

这种转换方式被称为 Unicode 转换格式(Unicode Transformation Format,简称为UTF),它又细分为 UTF-8、UTF-16、UTF-32 等等方式。我们最常用的是 UTF-8。为什么 UTF-8 最常用呢?因为它是可变长度的编码方案,针对不同的字符使用不同的字节数来编码,例如编码英文字母时,只需要一个字节(8个比特),而编码较复杂的汉字时,就会用到三个字节(24个比特)。

二进制的编码串可以说是给机器阅读的,为了方便,我们通常会将其转化为十六进制,例如“中”字的 Unicode 编码可以表示成 0x4e2d ,其 UTF-8 编码可以表示为0xe4b8ad ,'0x' 用于开头表示十六进制,这样就简洁多了。不过,UTF-8 编码的结果会被表示成以字节为单位的形式,例如“中”字用 UTF-8 编码后的字节形式是中 。

Python 中为了区分 Unicode 编码与字节码,分别在开头加“u”和“b”以示区分。在Python 3中,因为 Unicode 成了默认编码格式,所以“u”被省略掉了。

# 字符转 Unicode 编码
# Python3 中,开头的 u 被省略,b 不可省略
hex(ord('中')) >>> '0x4e2d'
hex(ord('A'))  >>> '0x41'

# 字符转 UTF-8 编码(encode)
'中'.encode('utf-8') >>> b'丬'
'A'.encode('utf-8')  >>> b'A'

# Unicode 编码还原成字符
chr(0x4e2d) >>> '中'
chr(0x41) >>> 'A'

# UTF-8 编码还原成字符(decode)
b'丬'.decode('utf-8') >>> '中'
b'A'.decode('utf-8') >>> 'A'

总结:Python 3 中的字符串是由 Unicode 码点组成的不可变序列,也就是由采用 Unicode 标准编码的字符组成的不可变序列。Unicode 编码将书写系统的字符映射成了计算机二进制数字,为了方便,通常显示为十六进制;在运算内存中,字符以 Unicode 编码呈现,当写入磁盘或用于网络传输时,一般采用 UTF-8 方式编码。

print(chr(10004),chr(10005))

for i in range(12):
    print(chr(9800+i),end=',')

✔ ✕
♈,♉,♊,♋,♌,♍,♎,♏,♐,♑,♒,♓

三、Python 教学 bytes


Python 1-16 bytes

在 Python3 以后,字符串和 bytes 类型彻底分开了。字符串是以字符为单位进行处理的,bytes 类型是以字节为单位处理的。

bytes 数据类型在所有的操作和使用甚至内置方法上和字符串数据类型基本一样,也是不可变的序列对象。

bytes 对象只负责以二进制字节序列的形式记录所需记录的对象,至于该对象到底表示什么(比如到底是什么字符)则由相应的编码格式解码所决定。Python3中,**bytes 通常用于网络数据传输、二进制图片和文件的保存**等等。可以通过调用 bytes() 生成 bytes 实例,其值形式为 b'xxxxx',其中 'xxxxx' 为一至多个转义的十六进制字符串(单个 x 的形式为:\x12,其中\x为小写的十六进制转义字符,12为二位十六进制数)组成的序列,每个十六进制数代表一个字节(八位二进制数,取值范围0-255),对于同一个字符串如果采用不同的编码方式生成 bytes 对象,就会形成不同的值.

创建方法:

b = b''         # 创建一个空的bytes
b = bytes()     # 创建一个空的bytes
b = b'hello'    #  直接指定这个hello是bytes类型
b = bytes('string',encoding='编码类型')  # 利用内置bytes方法,将字符串转换为指定编码的bytes
b = str.encode('编码类型')   # 利用字符串的encode方法编码成bytes,默认为utf-8类型

bytes.decode('编码类型'):将bytes对象解码成字符串,默认使用utf-8进行解码。

简单的省事模式:

string = b'xxxxxx'.decode() # 直接以默认的 utf-8 编码解码 bytes 成 string
b = string.encode() # 直接以默认的 utf-8 编码 string 为 bytes


 

 

 

上一篇:同比-环比


下一篇:数字三角形题解