看前须知

这里对本书中提到的不常见的内容进行了查证,举例,所以大家可以不用再费神去搜索相关内容

在Python中,我们运用“材料”来处理“事务”。
材料:操作对象,数据等
事务:加减乘除,拼接等

在Python中,数据以对象的形式出现,无论是Python提供的内置对象,还是使用Pyrhon或是像C扩展库等扩展语言工具创建的对象。对象是内存中的一部分,包含数值和相关操作的集合。
Python脚本中的一切都是对象。甚至简单的带有值(如99),或支持运算操作(加减乘除)的数字。

对象是Python中最基本的概念,这章将全面的体验Python的内置对象类型。

Python知识结构

Python的全貌:Python程序可以分解成模块、语句、表达式、对象。
· 程序由模块构成
· 模块包含语句
· 语句包含表达式
· 表达式创建并处理对象

本章将探索在编程过程使用的内置对象和表达式
在下一部分学习语句,语句是在管理对象。
在接触本书的“面向对象编程”的对象时,会发现我们是在模仿Python的内置对象类型来定义属于我们自己的对象类型。

在传统编程中,编程的三大支柱:顺序语句、选择语句、循环语句。
在Python中拥有全部这三类语句,同时也有一些相应的定义:函数和类。这些概念能帮你更早地建立思维模式,他们相对精巧和简洁。
列表推导的复杂表达式就是循环语句和选择语句的结合。而Python中的部分术语可能有多重含义。但在Python中,更为统一的原则就是对象,以及对象的操作。

为什么要使用内置类型

如果你是用过较底层的编程语言(C、C++,高级语言但对底层有良好衔接),应该知道很大一部分工作集中于使用对象(数据结构)去表现应用领域的组件。你需要部署内存结构、管理内存分配、实现搜索和读取例程等基础的操作,而Python则将这些操作整合成了内置类型,除非你有内置类型无法提供的特殊对象要处理,否则最好使用内置对象而不是用自己的实现。

· 内置对象使程序更容易编写。
对于简单的任务,内置类型往往能够表现问题领域的所有结构。Python直接提供了强大的工具,例如集合(列表)和搜索表(字典),你可以立即使用他们。仅是使用Python内置对象类型就能够完成很多工作。

· 内置对象使可扩展的组件。
对于较为复杂的任务,或许仍需要使用Python的类或C语言的接口提供你自己的对象。但我们手动实现的对象往往也是建立在内置类型的接触之上的。

· 内置对象往往比定制的数据结构更有效率。
Python的内置类型使用了已优化的用C实现的数据结构算法,尽管你可以实现属于自己的类似的数据类型,但往往很难达到内置数据类型所提供的性能水平。

· 内置对象是语言标准的一部分。
Python不但借鉴了一开内置工具的语言(如LISP),而且汲取了那些依靠程序员提供自己实现的工具或框架的语言(如C++)的优点。而且Python的内置工具使标准化的,一致的。

与我们从零开始创建的工具相比,内置对象类型不仅仅让编程变得更简单,而且他们也更强大和更高效。无论你是否实现新的对象类型,内置对象都构成了每一个Python程序的核心部分。

Python核心数据类型

内置类型,字面量(literal):字面量(literal)用于表达源代码中一个固定值的表示法(notation),整数、浮点数以及字符串等等都是字面量。字面量就是没有用标识符封装起来的量,是“值”的原始状态。

对象类型 字面量/构造示例
数字 1234,3.1415,3+4j,0b111,Decimal(),Fraction()
整数、浮点数、复数、二进制、高精度浮点数、分数
字符串 ‘spam’,“Bob’s”,b’a\x62c’,u’sp\xc4m’,r’a\b\c’
字符串,单双引号的应用,二进制、unicode、忽略转义
列表 [1,[2,‘three’],4.5],list(range(10))
示例,构造,range函数
字典 {‘food’:‘spam’,‘taste’:‘yum’},dict(hours=10)
示例,构造
元组 (1,‘spam’,4,‘U’),tuple(‘spam’),namedtuple
示例,构造,具名元组
文件 open(‘egg.txt’),open(r’C:\ham.bin’,‘wb’)
集合 set(‘abc’),{‘a’,‘b’,‘c’}
其他核心类型 类型、None、布尔型
程序单元类型 函数、模块、类
Python实现相关类型 已编译代码、调用栈跟踪

对于一些读者来说,表中的对象类型可能比你习惯的类型更通用也更强大。
例如,列表和字典就是强大的数据表现工具,省略了在使用低层语言的过程中为了支持集合和搜索而引入的绝大部份工作。列表提供了掐他对象的有序集合,而字典通过键存储对象。列表和字典都可以嵌套,可以随需求扩展和删减,并能够包含任意类型的对象。
字面量,常量和变量之间的区别
总结:字面量就是只能是赋值表达式中,在等号右侧的量。而对应着他,在等号左侧的就是变量。在Python中,很难说常量,一些模块中给一些变量赋值,看似常量,但是很多情况这个常量的值是可以再被赋值所改变的。例如pi。

>>> import math
>>> math.pi
3.141592653589793
>>> math.pi=3.14
>>> math.pi
3.14

而在C中,定义常量是可以被保护为只读的

const int i = 5;

而在Python中没有这个功能,虽然有网友自己定义了一个
Py tricks(1): python实现不可修改的常量

上表中,像函数、模块和类这样的编程单元,在Python中也是对象。
他们由def、class、import、lambda这样的语句和表达式创建,可以在脚本间自由的传递,存储在其他对象中,等等。

Python还提供了一组与实现相关的类型,例如编译过的代码对象,他们通常更多的关系到工具生成器而不是应用程序开发者?
这里不是很明白到底表达的什么意思,说的对象是.pyc等字节码,他们无法被修改,只是拿来用,所以只是工具?

选读:python里的强大工具生成器–yield

表中的内容并不一定完整,因为在Python程序中处理的每样东西都是对象。例如,在Python中进行文本模式匹配时,创建了模式对象(例如对文本的描述,或是处理描述的算法、函数,都是对象,只要是有形之物,都是对象);进行网络脚本编程时,使用了套接字对象。
这些其他类型的对象往往都是通过模块中导入或使用函数来建立的,例如在re和socket模块中的模式和套接字。而且他们都有各自的行为。这个就像是表中提到的Decimal()和Fraction(),这两个分别是decimal和fractions模块导入后,才能实现的类型,有自己的表达和计算方法。

通常把表中的对象类型乘坐核心数据类型,因为他们是在Python语言内部高效创建的,有一些特定语法可以生成他们:

>>> 'spam'

你正在运行一个字面量表达式,这个表达式生成并返回一个新的字符串对象。
这是Python用来生成这个对象的一个特定语法。类似的:[1] 列表,{‘a’:1} 字典,{1} 集合。
Python没有类型声明,运行的表达式的语法决定了创建和使用的对象的类型。
表中,那些对象生成表达式就是这些类型起源的地方。

一旦创建了一个对象,他就和操作集合绑定了,你只能对字符串进行字符串相关的操作,对列表进行列表相关的操作:
Python是动态类型的(他自动的跟踪你的类型而不是要求声明代码),但是他也是强类型语言(你只能对一个对象进行适合该类型的有效操作)。

>>> a=1+'1'
Traceback (most recent call last):File "<interactive input>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

弱类型 js、vbs:

>>> var a=1+'1'
>>> a
'11'

【转】静态类型语言的优势究竟是什么?已经有些年头了,不过感觉还不错。:总结
1、静态语言因为定义变量类型严格,而效率高:
我需要镊子,给你镊子。我需要一个金属制品,这样的,这样的,我猜你大概需要一个镊子。
每次执行时,程序需要考虑的东西的量就不一样,而且还附带着那些量后面的一堆东西,于是无论运行速度,还是执行模式代码的占用空间都不一样。
2、静态语言因为定义变量类型严格,而出错少:
当每条语句都要求必须是这样那样的类型时,他的如果存在潜在的bug,就会越早的暴露、被抹去。这使得成品有相对动态语言更强的可靠性。

(动态类型/静态类型)、(强类型/弱类型)、(编译/解释)

数字

Python的核心对象集合包括常规的类型:
整数(没有小数部分的数字)
浮点数(有小数部分的数字)
有虚部的复数
固定精度的十进制数
带分子和分母的有理数
以及全功能集合

Python内置的数字类型足以表示从你的年龄到你的银行存款的绝大部分数值量,同时还有第三方库提供更为强大的功能。

支持的运算:+ 加、- 减、* 乘、/ 除、**幂、%取余(模)等等,下一章将详细介绍数字类型这里只是简介

>>> 123+222
345
>>> 1.5*4
6.0
>>> 2**100
1267650600228229401496703205376
>>> 2**1000
10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376
>>> len(str(2**1000000)) #得出结果的显示的字符串长度,即位数的个数
301030

Python 十进制转二进制

很多类型都支持str和len,如果一些数值的意思得和打印的不一样,可以使用repr,他能展示数值的真实状态
上述的len、str代码,首先将运算结果利用内嵌的str函数转换成字符串,接着用len函数得到该字符串的长度。最后的结果就是位数的个数。

扩展阅读:Python的无限制边界的整数结构

>>> import sys
>>> t=0;i=0
>>> while t<100:
...     if (s:=sys.getsizeof(2**i))>t:
...         t=s
...         print(i,'\t',s )
...     i=i+1
...
0    28
30   32
60   36
90   40
120      44
150      48
180      52
210      56
240      60
270      64
300      68
330      72
360      76
390      80
420      84
450      88
480      92
510      96
540      100

在C和Java中,整数型都有特定长度的,整数型也因为存储长度和符号而取值范围不同。
但在Python中,整数型是没有长度限制的,限制整数长度的只有内存这个因素。
如上代码,整数的二进制长度每增加30位,存储就会增加4个字节,即32位。

def int_RAM():

大小端转换:struck !、字符串i:i+2、binascii.hexlify(binascii.unhexlify(data)[::-1])

python中如何查看指定内存地址的内容

1、读取内存中,整数相关的存储信息
随机生成整数,赋值给变量num
获取变量在内存中的地址,addr=id(num)
获取变量在内存中的占用空间,size=sizeof(num)
读取内存数据,btyes_=string_at(addr,size)
内存数据转HEX模式,btyes_.hex()

2、对HEX模式的字符串进行分割
上述整数,自1开始,每增加*2**30,存储就会增加4字节,虽然逻辑上觉得4字节是一个单位,每个字节串是小端存储,而每4个字节为一单位的单位间,也类似小端存储,但是在我写了一个模拟的转换程序后,发现其实数值部分,即这些4字节部分,是一条连贯的字节串,一个个的大小端转换后,结果就是一整条字节串的大小端转换:

l=list(range(16))
l1=[]
for i in range(0,len(l),4):l1=l[i+3:-(len(l)-i)-1:-1]+l1l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
l1
[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

这里的l[i+3:-(len(l)-i)-1:-1]是我经过一番探究后,最兼容也最低效的写法,简单的理解,相当于l[i:i+4][::-1],即每次读取4个字节,每次又把这4个字节逆转大小端,接下来是下4个字节,而这4个字节放在之前的4个字节前面。但结果其实就是整条逆转大小端。如果不是为了展示逆转后的每4个字节的两个空比特,4字节读取的同时可以去掉两个空比特,传递给新的比特串,若带着两个空比特逆转,完全可以一次性的逆转整个字节串。

Python 整数类型的内存读取和结构分析 代码

继续

>>> 3.1415*2
6.2830000000000004
>>> print(3.1415*2)
6.283

这是Python3.1前的版本显示

>>> 3.1415*2
6.283
>>> repr(3.1415)
'3.1415'

这是之后版本的显示,但实际上,按照内存中的结构的话,差一点的

>>> 3.1415*2
6.283
>>> repr(3.1415)
'3.1415'0100000000001001001000011100101011000000100000110001001001101111

底数区数值:1.5707500000000001
但是即便把这个数值复制出来,最后的小尾巴也是不存在的,大概是特有的舍去机制

扩展阅读:Python的float结构

我在之前的分析整数的代码中添加了暴力大小端转换数据区的部分,显示了大端序的hex和bin,和单精度浮点数并不一样!

>>> 0.5
0011 1111 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
>>> 1.0
0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
>>> 3.1415
0100 0000 0000 1001 0010 0001 1100 1010 1100 0000 1000 0011 0001 0010 0110 1111
>>> 2.0
0100 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

0.5在浮点数中是一个特殊的存在,因为在浮点表示时,1.0的数值区是0,指数区是‘0’,1.0是会在数指转换后,默认被加上去的
而浮点数的数值区第一个位到之后位的数值表示意义是:2**-1, 2**-2, 2**-3…,0.5正是2**-1 * 1,指数区是-1,数据区(底数)是1,而1在数据区的表示是0,所以与1.0的差别是指数区少一个1。用此可以验证该浮点数是否符合浮点数转换规则。
1.0 = 1*10**0
0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
第一个0表示正数
后面的011 1111 1111,表示10**0,10**e,而011 1111 1111,即2**

python - 接近完美的单精度浮点数转换代码
0.5
0 0111 1110 000 0000 0000 0000 0000 0000
1.0
0 0111 1111 000 0000 0000 0000 0000 0000
这个是单精度的浮点数结构,1比特的负号,8比特的指数,23比特的底数,共32位。
指数区取值范围是2**-127 ~ 2128
数据区取值范围是0~(2
-1+2**-2+…+2**-23)

那相对Python默认float,1比特的负号,11比特的指数,52比特的底数,共64位。是双精度符号位。
指数区取值范围是2**-1023 ~ 21023,即
数据区取值范围是0~(2
-1+2**-2+…+2**-52)
最大取值是,12**1024(2**-1+2**-2+…+2**-52)

f=0
for i in range(0,53):t=ff+=2**(i*-1)
print(t,'\n',f)1.9999999999999996
0011 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1110
1.9999999999999998
0011 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111

在码上面的一段时,我发现了之前的代码的一个bug,还发现了一个理解方式。

关于那个数值区计算后再加上个1的认知,可以理解为,二进制的数值区的那个隐性的1.0就是20,数值区第一位就是2-1,所以不需要专门的去加1,而是从2**0开始计算即可,而这个0是隐形于数值区的!

inf: 7ff0000000000000 0111 1111 1111
nan:    7ff8000000000000 0111 1111 1111 1
-inf:   fff0000000000000 1111 1111 1111

Python中定义7ff为正无穷:float(‘inf’)
所以最大指数只能到111 1111 1110,即2**1023
而nan只不存在的书,即比正无穷大的数是不存在的
inf带上符号就是负无穷了
以上是只能用float函数生成的特殊数值,无法用表达式赋值,而实际上如果手动修改数据的话

7ff8000000000001 : nan
float(2**1023) # 最大指数
7fe00000000000002**-1022
0010000000000000
2**-1023
0008000000000000 1000
2**-1024
0004000000000000 0100
2**-1025
0002000000000000 0010
2**-1023*1.5
000c000000000000 1100
2**-1023*1.75
000e000000000000 1110
2**-1022*1.5
0018000000000000 0001 1000
2**-1024*1.5
0006000000000000 0110
2**-1024*1.25
0005000000000000 0101

从2**-1023,规则变了,如果规则不练,则2**-1023就和0的结构一样,都是一串0
变了之后,可以有很多理解,我的逻辑是,一定出现的第一个1可以当作一个竖杠,前面多出来的x个0,当作2**-x,第一个1后面才开始按之前的逻辑处理。
仅看第一个1,指数最小的情况,就是这个1在末尾,即前面有51个0,即2**-51,此时指数位2**-1074

f=2**-1074
ctypes.string_at(id(f),24)[:15:-1].hex()
Out[276]: '0000000000000001'2**-1074*0.5
0.0
-2**-1074
8000000000000001
-2**-1074*0.5
-0.0
8000000000000000

此时是无法再添加任何数值了,

即最小的数值是2**-1074,最小的正数是2**-1074,最大的负数是-2**-1074,0不是正数,于是-0也不是负数。

f=0
for i in range(0,-53,-1):f=2**i+f>>> f
1.9999999999999998
3fffffffffffffff2**1023*1.9999999999999998
1.7976931348623157e+308
7fefffffffffffff

最大的数值是21023*(20+2**-1+2**-52)

继续

除了表达式外,随Python一起安装的还有一些常用的数学模块,模块只不过是我们导入以供使用的一些额外工具包。

>>> import math
>>> math.pi
3.141592653589793
>>> math.sqrt(85)
9.219544457292887

math模块包括更高级的数学工具,如函数,而random模块可以作为随机数字的生成器和随机选择器:

>>> import random
>>> random.random()
0.11326180328885771
>>> random.choice([1,2,3,4]) #列表,一个可包含任意类型元素的可变序列
2

Python还包括一些较为少见的数学对象:负数、固定精度十进制数、有理数、集合、布尔值等
和第三方开源扩展领域等:矩阵、向量、可扩展精度的数字、Decimal(高精度浮点数)、Fraction(分数)

到现在为止,我们已经把Python作为简单的计算器来使用。想要更好的利用内置类型,就来看一下字符串

字符串

字符串用来记录文本信息(你的名字)和任意的字节集合(如图片文件的内容)。

书中对字符串的定义包括字符字节串bytes,甚至还有第三方模块bitstring所使用的比特串。无论是str类型的变量还是bytes类型的变量,还是其他基于字符的类型。广义上都是字符串。

字符串是字符序列,它是一种抽象的概念,不能直接存储在硬盘;字节字符串是字节序列,它可以直接存储在硬盘。它们之间的映射被称为编码/解码。在Python中,程序中的文本都用字符串表示。

字节对象在内部是机器可读的形式,字符串仅是人类可读的形式。

我习惯的认为字符串是Python可以自动编解码识别的串,而无法被编解码的串,我习惯称之为字节串,甚至前面扩展内容的代码中还有比特串。但这里意味着所有单一连续的对象都是字符串。而不单一连续的,例如列表,他的实际内容存放的是元素地址,也就是说一串内存并不能完全展示列表的内容。所以不单一,因为通过地址连接元素,所以不连续。

他们是我们在Python中提到的第一个作为[不可变]序列(一个包含其他对象[字符/字节]的有序集合)的例子。序列中的元素包含了一个从左到右的顺序:序列中的元素根据他们的相对位置进行存储和读取。字符串是由单字符所组成的序列。其他更一般的序列类型好包括列表和元组。

序列操作

作为序列,字符串支持假设其中各个元素包含位置顺序的操作。

>>> S='Spam'
>>> len(S)
4
>>> S[0]
'S'
>>> S[1]
'p'

字符串具有不可变性,可变指的是存在改变变量内容而不改变变量地址的方法。而字符串的变量地址,直接包含了字符串的内容,而且不存在方法使得改变字符串内容而不改变地址。
相对可变内容的列表,他的地址中,数据区第一组记录元素数量,第二组指向元素们的地址串,在这个另外的地址中,元素们的地址挨个排列,可变的列表在增加、减少元素时,会改变元素记录数、生成对应的元素、将元素的地址添加入地址组中

在Python中,索引是按照从最前面的偏移量进行编码的,也就是从0开始,第一项索引为0,第二项索引为1,依此类推。

在Python中,不需要提前声明变量,可以直接给变量赋值,给一个变量赋值时就创建了他,可能赋值的是任何类型的对象。之后变量出现在表达式中的时候,就用其值替换它。
在使用变量之前,必须对其赋值。我们需要把一个对象赋值给一个变量,一边保存他供随后使用。

在Python中,我们能够反向索引,从最后一个开始(正向索引是从左边开始,反向索引是从右边开始)

>>> S[-1]
'm'
>>> S[-2]
'a'

负的索引号会与字符串的长度相加:
!!!

>>> S[-1]
'm'
>>> S[len(S)-1]
'm'

我之前在研究逆序的时候,这样思考过,但是个人向的这样思考只是一种思考方式,而老师这么说了,万一Python真的就是这么做的呢,于是就变成了定理

方括号中可以是:字面量、变量、表达式,只要结果能够表示正数,甚至于布尔值都可以

除了索引,序列也支持分片(slice,切片)操作:

>>> S[1:3]
'pa'

从一个字符串中依次就提取出一部分的方法。
X[I:J] 表示“取出在X中,从偏移量为I,直到但不包括偏移量为J的内容”。
结果就是返回一个新的对象。如上,获得了1、2两个字符(1到3的所有字符)作为一个新的字符串。效果就是切片或“分理出”中间的两个字符

在分片操作中,左边界默认为0,又便捷默认为分片序列的长度,于是就有了以下写法:

S[:]
'Spam'
S[1:]
'pam'
S[0:3]
'Spa'
S[:3]
'Spa'
S[:-1]
'Spa'

作为一个序列,字符串也支持使用加号进行拼接(Concatenation),将两个字符串合并成一个新的字符串,或者重复,通过再重复依次创建一个新的字符串。

>>> S
'Spam'
>>> S+'xyz'
'Spamxyz'
>>> S*8
'SpamSpamSpamSpamSpamSpamSpamSpam'

扩展阅读

生成指定内存大小的变量

import mem
mem.mem()
s=' '*2**20*100
mem.mem()
list(s[::-1])
mem.mem()
input()

我写了一段代码,查看切片对于内存的占用,这里的打印结果

内存占用:14.32 MB
内存占用:114.33 MB
内存占用:114.33 MB

我对于切片的写法从s[:],到list(s[:]),因为我很确信切片其实是占用了内存的,只不过因为之上语句上下并没有多出的变量,python迅速清空了无用数据,所以在语句处理完后,内存也被清理,看似内存一样,但使用list语句后,耗时很长,在任务管理器中看到内存一度占用1GB以上。
我有个新想法,于是将上面list语句赋值给变量l,当内存不再增长后,也不会倒退,说明其实list语句从执行到赋值变量,他的空间没有变过。
我的电脑,剩余内存有4G,我生成一个2G的数据,再切片,看看过程变化,再生成一个4G的看看!
如果切片写法是s[:],python是不进行任何处理的,他会把他当作s看待,当指定索引且片段不是整个s时,这个的过程是会生成一个副本的。
如果逆序输出,更是如此。而同一个片段,逆序操作耗时更多。
另,以上操作,例如生成2G大小的字符串,python会先升到2.5G,再落到2G。如果使用s=b’\x00’2**302,生成2G的字节,会先升到3G再落下。如果改写成i=2**30*2;s=b’\x00’*i,则会恰到好处,于是原因应该是运算过程的中间量,学到了!

索引、切片、逆序的关系

正向索引:len(s)+反向索引坐标,len(s)-|反向索引坐标|
反向索引:len(s)+反向索引坐标,len(s)-|反向索引坐标|

书中提到正向索引,s[:] 默认的两端数值是0、len(s)
这一点在逆序时极为重要
s[::-1] 默认的两端数值就是-1、-(len(s)+1)
如果不使用逆向索引,去写逆序时,s[0]只能用默认的空来表示,这个在数据处理时很不友好,而使用了逆向索引,一切问题迎刃而解。

至于那种写法更效率,我之前写了一堆,貌似用if判断是否是0,拎出来单独一个写法,其他写法则是很普通的过程,反而是最效率的,而搞成很兼容的方法去写,反而不高效,关键是兼容的写法的数值换算。

我一会再对其深入下。

逆向写法的记忆思路:
1、逆向的第一个冒号两边,冒号右侧的索引位置在冒号左侧的索引位置的右边
2、想得到123的逆序,即321,这样在脑中一念叨,自然逆序写法的起始在3,终止在0,而这样想的话,方法1反而没必要了。但这个是写什么,而方法1是怎么写对。

步进,从起点开始,每隔个步进,输出一个对应位置上的元素

索引和range是一致的

range可以当作整数序列,其实他的本质只是一个类型,只存储了元素数、起始、终止、步进这四个元素,但他的写法和索引是差不多的

list(range(0,10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(0,10,-1))
[]
>>> list(range(10,0,-1))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

range的逆序输出和索引一样,左侧的索引在右侧的索引的实际右侧,记录从左侧的索引开始,不包含第一个逗号右侧索引的元素

索引和二进制转十进制

另外,索引的思路很适合二进制换算,虽然自然看来,二进制的低位是右侧

例如:1010,即8421中的8+2=10
但是我经常误认为,应该是24+22,但应该是23+21

所以先把二进制绑定为索引的思维模式:

1 0 1 0
3 2 1 0

二进制低位到高位,在索引看来,就是从0开始,这也是从0开始的妙处!

多态

加号对于不同的对象有不同的意义:用于数字,表示加法;用于字符串,表示拼接。
这是Python的一般特性,即多态,即一个操作的意义取决于被操作的对象。正如将在学习动态类型时看到的那样,这种多态的特性给Python代码带来了很大的简洁性和灵活性。
由于类型并不受约数,Python编写的操作通常可以自动的适用于不同类型的对象,只要他们支持一种兼容的接口。

寻求帮助

尽管序列操作是通用的,但是方法不通用(虽然某些类型共享某些方法名,字符串的方法只能用于字符串)。
Python的工具库是呈层级分布的:可作用于多种类型的通用操作都是以内置函数或表达式的形式出现的(如len(X)、X[0]),但类型特定的操作是以方法调用的形式出现的(如aString.upper())。如果经常使用Python,你会更顺利的从这些分类中找到你所需要的工具。

本书并不会详尽的介绍对象方法,对于更多细节,你可以调用内置的dir函数。
这个函数列出了在调用者作用域内,形式参数的默认值;他会返回一个列表,其中包含了对象的所有属性。由于方法是函数属性,他们也会在这个列表中。假设S是一个字符串:

每个版本的类中的函数,都可能有所不同,例如我用的3.9.1就比书中版本多了了’__init_subclass__’、‘isascii’、‘removeprefix’、‘removesuffix’

>>> dir(S)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
'__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs',
'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal',
'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle',
'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition',
'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition',
'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title',
'translate', 'upper', 'zfill']

也许只有在本书的稍后部分你才会对这个列表的变量名中有双下划线的部分感兴趣,那时我们将在类中学习重载:他们代表了字符串对象的实现方式,并支持定制。例如字符串的__add__方法是真正执行字符串拼接的函数。虽然Python内部将前者映射到后者,但是你也应当尽量避免直接使用第二种形式。

'Spam'+'NI!' # 15.5 ns
'Spam'.__add__('NI!') # 199 ns
s1+s2 # 129 ns
s1+'NI!' # 118 ns
s1.__add__(s2) # 228 ns

行3相对行1是从变量中读取的数据,而行4只有一个数据来自于变量,于是看来,行1全是在核心层的操作,无论是数据还是方法,而其他的都调用了相对较外的操作,例如读取变量内容、读取函数。于是可以推测,即便字符串+的方法却是来自于str.add,但是在Python进程初始化的时候,这些操作就已经从__add__加载到核心中了,所以只有数据和+的操作飞起。同样飞起的操作还有:

if False:pass # 15.5 ns
len(S) # 110 ns
len('Spam') # 91.7 ns
S.__len__() # 126 ns
'Spam'.__len__() # 112 ns
str.__len__(S) # 163 ns
str.__len__('Spam') # 151 ns

一般来说,以双下划线开头并结尾的变量名用来表示Python实现细节的命名模式。而这个列表中没有下划线的属性是字符串对象能够调用的方法。

dir函数简单的给出了方法的名称,要查询他们是做什么的,可以将其传递给help函数:

>>>help(S.replace)
Help on built-in function replace:replace(old, new, count=-1, /) method of builtins.str instanceReturn a copy with all occurrences of substring old replaced by new.countMaximum number of occurrences to replace.-1 (the default value) means replace all occurrences.If the optional argument count is given, only the first count occurrences arereplaced.

就像PyDoc(一个从对象中提取文档并生成html的工具)意义,help是一个随Python一起安装的面向系统代码的接口。

dir和help,命令都可以作用于一个真实对象(比如这里的字符串变量S或者字符串’Spam’)或是一种数据类型(如str、list和dict)。
其中help命令相对于dir命令而言,在返回相同的函数列表的同时,还提供了完整的类型细节,并允许你使用类名查询一个具体的方法(例如str.replace)。
想获得更多的细节,可以参考Python的标准库参考手册或者商业出版的参考书,但是dir和help提供了Python中最原生的文档。

虽然int和str下都有__add__,他们的说明也一模一样,但是他们的操作过程和意义是不一样的,int的意义是十进制加法,过程是把整数结构转化成二进制并进行二进制加法运算,再返回二进制运算的结果,转化成十进制,其中过程可能比描述的更为复杂。
而str.__add__,是把两个字符串的内容依照次序,复制到一个新的空间中,形成一个新的字符串。当然这个字符串可能立刻就用,然后被清理掉,也可能赋值给一个新的变量,方便重复使用。
因为有时需要int的二进制长度,所以需要len的方法,但是len这个词对于整数没有明确的意义,是指整数的位数(个十百千),还是对应的二进制长度,还是整数结构的长度,作为高级语言,我也不鼓励大家研究类型在内存中的结构,因为我为此前后被坑过一周多了,虽然现在玩的比较遛,但是Python的其中一个目的就是不需要我们关注类型和内存的细节,但我忍不住…
咳咳~ 所以int中,没有__len__,但是有一个专属的bit_length。而sys模块中有一个相对于python系统的getsizeof来获取变量的所占空间,计算方法貌似是设计双层结构,例如列表,一层结构是固定的大小,但是二层结构是变动的等等,但这都是细节,真的不要深究了,不然你更适合学C。
这类方法可以自定义中被覆盖掉,很好用的样子。

不可变性

在之前的例子中,没有通过任何操作对原始的字符串进行改变。每个字符串操作都生成了新的字符串,因为字符串在Python中具有不可变性:在创建后,不能原位置(in place)改变。
即,你永远不能覆盖不可变对象的值(正常操作下)。例如不能通过对其某一个位置进行赋值而改变字符串,但你总是可以建立一个新的字符串并以同一个变量名对其进行赋值。而Python在运行过程中会清理旧的对象。

>>> S
'Spam'
>>> id(S)
1845606364400
>>> S[0]='z'
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> S='z'+S[1:]
>>> S
'zpam'
>>> id(S)
1845606364144

其中id(S),返回S变量在内存中的地址
看到后面使用运算表达式对S赋值后,S的地址变了
至于S改变的过程,

>>> a=666
>>> id(a)
1566707025552
>>> del a
>>> a=' '*2**30*4

我获取id(a)的数值后,在计算器中计算出其十六进制数值 16CC7040690 然后在HxD中搜索python进程的对应小端字符串,很容易就能找到地址,这个地址不是固定的,如下

在这里del a后,对应位置会清零,在这里创建其他变量,会生成变量名和变量地址,假设这就是变量名储存区域。我写一个耗时较长的表达式,当表达式运算时,这里并没有变量生成,于是确定,是先生成的数值,再根据数值的地址生成了变量。

Python中的每一个对象都可以归类为不可变的或者可变的。
在核心类型中,数字、字符串、元组,是不可变的;列表、字典、集合,是可变的,他们可以跟你用类创造出的对象一样,完全自由的改变。

你可以在原位置改变基于文本的数据,这需要你将它扩展成一个独立字符构成的列表,然后不加入其它字符重新把它拼接起来。另一种方法是bytearray。

>>> S='Spam'
>>> L=list(S)
>>> L
['S', 'p', 'a', 'm']
>>> L[0]='z'
>>> ''.join(L)
'zpam'
>>> B=bytearray(b'spam')
>>> B.extend(b'eggs')
>>> B
bytearray(b'spameggs')
>>> B.decode()
'spameggs'>>> bytearray('香'.encode())
bytearray(b'\xe9\xa6\x99')

bytearray存放的是字节,但str存放的中文通常是以unicode ord实现的,而非UTF编码。

但我刚想到,unicode的长度是不定的,有1字节的,如ascii;有2字节的,如中文;还有3字节的,如哥特字母,但这类集序大于2字节的统一用4字节表示。
那他肯定有辅助区来标记这些unicode的占位长度,而不是单纯的一串unicode

>>> data('aa')
02 00 00 00 00 00 00 00 38 7b d2 ea dc 13 50 17
e5 51 93 11 5f 11 52 11 00 00 00 00 00 00 00 00
61 61 00
>>> data('慡慡')
02 00 00 00 00 00 00 00 b4 11 f2 7f c1 66 29 83
a8 00 00 00 00 00 00 00 b8 75 cd 7d 49 01 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
02 00 00 00 00 00 00 00 61 61 61 61 00 00
>>> data('\U00016161\U00016161慡aa')
05 00 00 00 00 00 00 00 02 b1 cf 5f 8a 8f 6f 15
b0 00 00 9f 00 12 51 77 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 61 61 01 00 61 61 01 00
61 61 00 00 61 00 00 00 61 00 00 00 00 00 00 00
>>> bin(0xa8)
'0b10101000'
>>> bin(0xb0)
'0b10110000'
>>> s='\U00016161\U00016161慡aaaa'
>>> s
'\U00016161\U00016161慡aaaa'
>>> id(s)
1415155147136
#之后使用HxD将b0改成a8
>>> s
'慡\x01慡\x01慡\x00a'
# 用HxD将字符数修改为9
>>> s
'慡\x01慡\x01慡\x00a\x00a'

经过多次对比,包含中文字符的会在第二行有a8的标记,包含超级unicode字符的,会有b0的标记,就是利用这个标记记录字符串中最大unicode占用字节数的,如果用这个思路去拼接几个字符串,可以先获取这几个字符串中最大字符的字节占用,直接读取标记,然后都转换成对应字节长度的unicode,拼接,而因为暂时无法获知解码方法,就走旁门左道,生成一个对应长度的字符串,覆盖其数据。但是我现在并未知晓写入内存数据的方法,而且我也真的懒得搞了~

b=bytearray(b'')
for i in range(1000):b.extend('香'.encode())
280 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)b=bytearray(b'')
x='香'.encode()for i in range(1000):b.extend(x)
140 µs ± 2.72 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)l=[]
for i in range(1000):l.append('香')
102 µs ± 592 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)''.join(l)
20.4 µs ± 316 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
b.decode()
6.16 µs ± 42.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)l=['香'*500,'香'*500]
''.join(l)
487 ns ± 2.95 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

列表转字符串相对来说慢一点,但是间隔符的可操作性强,而且带上之前的追加操作,列表更省性能。

bb=bitstring.BitArray()
for i in range(1000):bb.append(b)
5.77 ms ± 26.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)bb.bytes.decode()
10.8 µs ± 183 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

首先bit的操作数是bytes的8倍,加之这是个第三方的软件,效率不高是常见的。
所以最好的方法就是最常用的方法,这大概也是为什么我是第一次见到bytearray这个类型吧!

指定类型的方法

目前我们学过的每一个字符串操作都是一个真正序列操作。也就是说这些操作在Python中的其他序列也能使用,包括列表和元组。
除了一般的序列操作,字符串还有独有的一些作为方法存在的操作。方法指的是依赖并作用于对象上的函数,并通过一个调用表达式触发。
例如,字符串的find方法是一个基本的子字符串查找的操作(返回一个传入子字符串的偏移量,没找到的情况下返回-1)。
而字符串的replace方法对全局进行搜索和替换。
这两种操作都针对他们所依赖和被调用的对象而进行。

>>> S='Spam'
>>> S.find('pa')
1
>>> S.replace('pa','XYZ')
'SXYZm'
>>> S
'Spam'

尽管这些字符串方法的命名有改变的含义,但在这里都不会改变原始的字符串,而是会创建一个新的字符串作为结果,因为字符串具有不可变性,这种做法是唯一存在的一种可能。
字符串方法是Python中文本处理的头号工具。其他的方法还能够实现:
大小写变换,检测字符串的内容(数字、字母等)、去掉字符串后的空格字符、通过分隔符将字符拆分为子字符串(推导式comprehensions(又称解析式),是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。)

>>> line='a,bb,cc,d'
>>> line.split(',')
['a', 'bb', 'cc', 'd']
>>> S='Spam'
>>> S.upper()
'SPAM'
>>> S.isalpha()
True
>>> line='a,bb,cc,d  \t  \n'
>>> line.rstrip()
'a,bb,cc,d'
>>> line.rstrip().split(',')
['a', 'bb', 'cc', 'd']

这里的最后一行命令,他在调用split()方法前调用了rstrip()方法。Python遵循从左到右的执行顺序,每次前一步方法调用结束,都会为后一部方法调用产生一个临时对象。

上述从左到右,但是还有个东西叫做优先级,例如表达式中包含算术运算幂**的话,他会优先算幂,再把得出的结果和后面或前面的变量一起算的。而赋值符号=,也可以把他看作最低优先级。如果不确定优先级或者有需求的话,可以无脑加圆括号括起来。
字符串还支持一个叫做格式化的高级替代操作,可以以一个表达式的形式(最初的)和一个字符串方法调用形式使用:

'%s, eggs, and %s'%('spam', 'SPAM!')
'spam, eggs, and SPAM!'
>>> '{0}, eggs, end {1}'.format('spam', 'SPAM!')
'spam, eggs, end SPAM!'
>>> '{}, eggs, end {}'.format('spam', 'SPAM!')
'spam, eggs, end SPAM!'

{}自动对应后面字符串或变量,{0}为手动指定,不能同时用

>>> '{:,.2f}'.format(296999.2567)
'296,999.26'
>>> '%.2f | %+05d'%(3.14159, -42)
'3.14 | -0042'

扩展:str的所有方法分类归纳???

字符串编程的其他方式

到目前为止,我们学习了字符串对象的序列操作方法和类型特定的方法。
Python还提供了各种便携字符串的方法,转义字符:

>>> S='A\nB\tC'
>>> len(S)
5
>>> ord('\n')
10
>>> S='A\0B\0C'
>>> len(S)
5
>>> S
'A\x00B\x00C'

Python允许字符串包括在单引号或双引号中,他们是相同的,而采用不同的引号可以让另外一种引号被包含在其中(大多数程序员倾向于使用单引号)。

Python也允许在三个引号(单引号或双引号)中包括多行字符串字面量。当采用这种形式的时候,所有的行都合并在一起,并在每一行的末尾增加换行符。这是一个语法上微妙的便捷方式,当在Python脚本中嵌入像多行HTML、XML或JSON这样的代码时十分有用。这种方式能暂时减少代码行数,仅需要在代码段上都加上三个双引号。

1、自动在每行增加\n
2、支持括注的内容内的其他引号,只要不与开始的三个引号造成配对结束
3、在shell中,三个引号后回车,会不执行语句而继续输入

>>> s='''
... aaa
... b'""''b
... ccc
... '''
>>> s
'\naaa\nb\'""\'\'b\nccc\n'
>>> len(s)
17
>>> print(s)aaa
b'""''b
ccc>>> repr(s)
'\'\\naaa\\nb\\\'""\\\'\\\'b\\nccc\\n\''
>>> for i in s:
...     print(repr(i),end='|')
...
'\n'|'a'|'a'|'a'|'\n'|'b'|"'"|'"'|'"'|"'"|"'"|'b'|'\n'|'c'|'c'|'c'|'\n'|
>>> for i in s:
...     print(hex(ord(i))[2:].rjust(2,'0'),end=' ')
...
0a 61 61 61 0a 62 27 22 22 27 27 62 0a 63 63 63 0a
>>> ctypes.string_at(id(s)+48,sys.getsizeof(s)-49).hex(' ')
'0a 61 61 61 0a 62 27 22 22 27 27 62 0a 63 63 63 0a'

最后一行是我根据str类的结构获取的在内存中的形态,其实就是unicode字序,之上代码。

Python也支持原始(raw)字符字面量,即去掉反斜线转移机制。这样的字符串字面量是以字母’r’开头,并对注入Windows下的文件路径的表示十分有用(如r’C:\text\new’)

>>> 'C:\code\temp.txt'
'C:\\code\temp.txt'
>>> open('C:\code\temp.txt','rb')
OSError: [Errno 22] Invalid argument: 'C:\\code\temp.txt'
>>> open(r'C:\code\temp.txt','rb')
<_io.BufferedReader name='C:\\code\\temp.txt'>
>>> open('C:/code/temp.txt','rb')
<_io.BufferedReader name='C:/code/temp.txt'>

Unicode字符串

Unicode 字符百科 这个界面很友好
Unicode compart 这个给出
font space 这个更方便查字体
字客网 这个可以显示包含的子集了更多的字符信息
Unicode的文本处理二三事
字符编码简明教程
每一个程序员必须掌握的知识,字符集与字符编码
一图弄懂ASCII、GB2312、GBK、GB18030编码
各种编码格式(GB2312,GBK,GB18030,unicode,utf-8)之间的关系
刨根究底字符编码
Python的标准编码
如何以编程方式查找Python已知的编解码器列表?
标准编码文件所在目录:Python\Lib\encodings

中文字符集与字符编码的基础知识
GB 2312-1980 信息交换用汉字编码字符集基本集

常用信息编码
字符集是标准,字符编码是实现。
补充:GB2312
一级汉字:按拼音排,若音同,按笔画排
二级汉字:按部首排,再按笔画排

'你'.encode('gb2312')
Out[3]: b'\xc4\xe3''尼'.encode('gb2312')
Out[4]: b'\xc4\xe1'for i in range(0xc4e1-10,0xc4e1+10):print(i.to_bytes(length=2,byteorder='big').decode('gb2312'),end=' ')
淖 呢 馁 内 嫩 能 妮 霓 倪 泥 尼 拟 你 匿 腻 逆 溺 蔫 拈 年 for i in range(b:=int.from_bytes('镧'.encode('gb2312'),byteorder='big')-10,b+10):print((bytes.fromhex(hex(i)[2:])).decode('gb2312'),end=' ')镙 镛 镞 镟 镝 镡 镢 镤 镥 镦 for i in range(int.from_bytes('阿'.encode('gb2312'),byteorder='big')):try:s=int.to_bytes(i,length=2,byteorder='big').decode('gb2312')except:passelse:if s.isprintable():print(hex(i)[2:],s,end='\t')
7e7e ~~ a1a2 、
bin(0xa1a2)
Out[50]: '0b1010000110100010'

上面最后一段代码,表示的是本地编码中,除了ascii首位是0的(0~7f),其他部分字符的每个字节都以1开头。
机内码=国标码+0x8080
国标码=区位码+0x2020
机内码=区位码+0xa0a0
通用编码字符集:UCS、Unicode、CJK(中日韩)
汉字字形码、汉字地址码(字体、字库)




Font 是从 character 到 glyph 的桥梁。
Font 根据 character 这一抽象输入提供 glyph 这一具象输出。
Font 的本质是个存储了 character 与 glyph 的映射方式(程序的一面)以及 glyph 图形(设计的一面)的数据库。

'\u4e00'
Out[8]: '一'

如果记事本等软件都是Unicode标准的话,文件打开是个很复杂的过程!

例如,我现在打开一个用ANSI(gb2312)保存的文件的话,加载到内存中的字符串是Unicode集序(UCS-2/UTF-16 编码),字体的显示也是Unicode字符集。
UCS-2和UTF-8是Unicode的实现方式。而gb2312编码保存的文件,存储字节是机器码,是内码的实现方式(+a0a0)。

for i in range(20320-10,20320+10):print(chr(i),end=' ')佖 佗 佘 余 佚 佛 作 佝 佞 佟 你 佡 佢 佣 佤 佥 佦 佧 佨 佩

而我试了下,日语,一个字符居然占8个字节…

for i in '原因この現象は':print(i,'\t',i.encode('ISO-2022-JP'))原   b'\x1b$B86\x1b(B'
因    b'\x1b$B0x\x1b(B'
こ    b'\x1b$B$3\x1b(B'
の    b'\x1b$B$N\x1b(B'
現    b'\x1b$B8=\x1b(B'
象    b'\x1b$B>]\x1b(B'
は    b'\x1b$B$O\x1b(B'
'123原因こ456の現象abcは'.encode('ISO-2022-JP')
Out[8]: b'123\x1b$B860x$3\x1b(B456\x1b$B$N8=>]\x1b(Babc\x1b$B$O\x1b(B'

无语

'香香'.encode("raw_unicode_escape")
Out[183]: b'\\u9999\\u9999'
print('香香'.encode("raw_unicode_escape").decode())
\u9999\u9999

特殊的编码

Unicode 13.0 字符代码图表 chardet -
Python中的字符编码自动检测模块
Code Page Identifiers
比较全的字符编码
关于Windows记事本的ANSI编码:美国国家标准学会( American National Standards Institute)

ANSI本身的意思并非是本地编码,而在Windows上是被当作本地编码的原因,ANSI在美国当地是本地编码,可能是翻译上或者编码繁杂等原因,ANSI就对应了系统语言的编码。

在cmd上查看和修改cmd的本地编码:
C:\Users\Jone>chcp
活动代码页: 936
C:\Users\Jone>chcp
65001 Active code page: 65001

表 A.5. ANSI和OEM共有的DBCS Code Page 代码页Code Page 对应的字符集Character Set Code
Page 932 Japanese Code
Page 936 GBK - Simplified Chinese Code
Page 949 Korean Code
Page 950 BIG5 - Traditional Chinese

Python还支持完整的Unicode字符串形式,从而支持处理国际化的字符文本,例如日文和俄文的基本字符,并没有被编码在ASCII字符集中。这种非ASCII字符能够在网页、Email、图形界面、JSON和XML等情形下被展示。处理这样的字符需要Unicode的支持。

>>> 'sp\xc4m'
'spÄm'
>>> b'sp\xc4m'
b'sp\xc4m'
>>> '\x0'
truncated \xXX escape
>>> '\xFF'
'ÿ'
>>> '\XFF'
'\\XFF'
>>> 'sp\u00c4m'
'spÄm'
>>> '\x6161'
'a61'
>>> '\x61'
'a'
>>> '\u6161'
'慡'
>>> '\u61'
truncated \uXXXX escape
>>> '\u0061'
'a'
>>> '\u0001'
'\x01'
>>> '\U00000061'
'a'

str字符串在内存中是以Unicode字符集顺序存储的,用bytes字符串类型表示原始字节值。
当字符串中仅有ascii等用8比特表示的字符时,所有字符都只有8比特即1字节的长度。
如果存在一个16bit的字符,那么所有的字符就用16bit表示。
同样存在一个32bit的字符,所有字符就都扩展为32bit表示。

1、\x16进制会自动转换成字符,且后面必须有两个16进制的数字,X必须是大写,但是后面的十六进制不分大小写
2、bytes显示,只有可显示的ascii会显示为字符
3、\u,u小写,后面必须带4个十六进制(2个字节),不分大小写
4、\U,U大写,后面必须带8个十六进制(4个字节),不分大小写
\x、\u、\U都是Unicode的表示方式,分别支持2位、4位、8位的Unicode

字符集总结

关于字符集和字符编码:字符集是一种统一标准,变量存储在内存中的是字符集的顺序。
字符编码是一种实用标准,Python3默认使用utf16作为默认字符编码,当读取源代码,写入文件时,都默认使用utf16,也可以指定其他编码。

'spam'
Out[1]: 'spam''spam'.encode() # 不填即是默认值'utf8'
Out[2]: b'spam''spam'.encode('utf16')
Out[3]: b'\xff\xfes\x00p\x00a\x00m\x00''香spam香'.encode()
Out[6]: b'\xe9\xa6\x99spam\xe9\xa6\x99'

下面代码中内存形态是字符串变量在内存中的存储

ctypes.string_at(id(d)+16,sys.getsizeof(d)-16).hex(' ')内存形态('spam') # 不做任何处理,在第三行开始记录unicode
04 00 00 00 00 00 00 00 b8 37 f4 de 45 60 96 0f
e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
73 70 61 6d 00
内存形态('香spam香') # 标记为a8,每隔字符长度为2字节,在第二行后面记录字符所在内存地址,虽然通常在第四行后面就开始记录unicode
06 00 00 00 00 00 00 00 cb f7 c0 46 61 c1 9b a3
a8 00 00 00 00 00 00 00 18 a6 ec 3d dc 02 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
06 00 00 00 00 00 00 00 99 99 73 00 70 00 61 00
6d 00 99 99 00 00
'\U0001f606香spam香'
Out[18]: '												

第4章 介绍Python对象类型相关推荐

  1. 《Python 学习手册4th》 第四章 介绍Python对象类型

    ''' 时间: 9月5日 - 9月30日 要求: 1. 书本内容总结归纳,整理在博客园笔记上传 2. 完成所有课后习题 注:"#" 后加的是备注内容(每天看42页内容,可以保证月底 ...

  2. 类型列表Python 学习手册 第二部分 类型与运算 第4章 介绍Python对象类型

    这几周一直在查找类型列表之类的问题,上午正好有机会和大家讨论一下. 第二分部 类型与算运   第四章 绍介Python象对类型   形成: 象对 --> 表达式 --> 语句 --> ...

  3. 第4章:介绍python对象类型/4.1 python的核心数据类型/4.7 集合

    集合概念 集合类似字典,也是用大括号括起来的{ } 元素之间用逗号隔开 元素在集合中是唯一的 集合元素允许修改和删除,但是元素本身的值不能修改 集合是没有顺序的,所以不能通过下标获取集合的某个元素 集 ...

  4. Python对象类型

    Python对象类型 Python进阶(二)--Python对象类型 上一章中我们主要讲了Python的安装与Python基本命令行,IDLE的应用.本章中我们将讲述Python的对象类型,包括数字. ...

  5. 《看漫画学python》第1章介绍python的历史和特点

    30年前,第一个Python编译器问世,标志着Python的第一个版本正式诞生. 30年后,Python成为了名副其实的最受欢迎程序设计语言之一,甚至在中小学里也掀起了Python狂潮. 经过30年的 ...

  6. python 对象类型有哪些?

    python 强大的内置类型让我接触到python的时候开始慢慢的喜欢上它了,感觉既方便又好用,下面我们先一起学习下内置对象类型的好处: 1内置对象能够使得我们编写程序更容易. 2内置的对象效率更高, ...

  7. Python对象类型及相关操作

    文章目录 Python对象类型 对象操作函数 1.数字类型 常用的算术运算符: 数字运算相关的内置函数: math模块中的常用函数: 2.字符串 1.字符编码 2.字符串表示 3.转义字符串 4.字符 ...

  8. Python对象类型——字符串、列表、元组

    字符串 Python连接多个字符串可用"+"号,但这个操作不如把所有子字符串放到一个列表或可迭代对象中,然后调用一个join方法来把所有内容连接在一起节约内存. 原始字符串操作符( ...

  9. python对象类型及其运算 数字 字符串 list dict tupe dict

    python内置对象的类型及其所支持的运算 我们在编程时为什么要使用内置对象类型,以及我们在编程时尽可能使用自定义类型呢还是但凡有可能都去使用内置类型.很显然,对于python而言,内置类型更容易理解 ...

最新文章

  1. 说说大型高并发高负载网站的系统架构【转】
  2. (Asp.Net)转载-用Powershell 建立IIS web site
  3. python面向对象三大特性之继承
  4. 新技术驱动新商业,网易创新企业大会亮点抢先看!
  5. 【maven】改造已有项目
  6. 一所传闻要被“降级”的211高校,让这位网红教授“救活了”
  7. P3959-宝藏【模拟退火】
  8. atitit.attilax的软件 架构 理念.docx 1. Atitit 软件设计的模型 frm lib standard 框架类库标准 FLS模型 2. fusco 3. Cirx
  9. MySQL客户端安装
  10. android 设备管理和凭证,简述设备管理的涵义
  11. sql server中binary怎么得到char类型
  12. 大数据时代,你应该具备的大数据思维
  13. 初学者如何学习一门新的计算机语言!!!
  14. Android 源码分析工具
  15. 计算机专业白色简历封面,计算机专业个人简历封面模板图
  16. 英文字母html,利用HTML5实现英文字母ABCD动画特效
  17. python手机摄像头投测距_python opencv单目测距 小孔成像原理
  18. 项目上线后中英文翻译问题解决
  19. laravel Carbon 时间处理类使用
  20. ccleaner-ccleaner下载

热门文章

  1. 搞懂大数据,这篇文章一定要细细品读! 大数据
  2. 差分时钟信号的使用与引脚绑定(ucf)
  3. SQL注入_数据库基础
  4. Oracle 函数(字符、数值)
  5. Excel常用函数(一)
  6. 5.30黄金空头能否延续?今日多空如何布局?
  7. Unity-机器码加密
  8. nes模拟器java怎么用_virtuanes模拟器怎么使用?virtuanes模拟器图文教程(附软件下载)...
  9. 当爬虫工程师需要学习什么
  10. 基于uniapp在微信支付宝小程序中使用发券插件