6. 小数据池-编码-文件操作
一、小数据池
1. 小数据池定义
小数据池(常量池),一种数据缓存机制,也被称为驻留机制。小数据池只针对:整数、字符串、布尔值。其他数据类型不存在驻留机制。
2. 各类型数据池限定
(1) 整型
在python中 -5 ~ 256 之间的整数会被驻留在内存中。每次使用都是同一个对象。
(2) 字符串
将一定规则的字符串缓存。在使用的时候,内存中只会创建一个该数据的对象。保存在小数据池中。当使用的时候直接从小数据池中获取对象的内存应用。而不需要创建一个新的数据,这样会节省更多的内存区域。
优点:能提高一些字符串,整数的处理速度。省略创建对象的过程
缺点:在“池”中创建或插入新的内容会花费更多的时间
a. 如果字符串的长度是0或者1, 都会默认进行缓存
b. 字符串长度大于1, 但是字符串中只包含字母, 数字, 下划线时才会缓存
c. 用乘法得到的字符串.
①. 乘数为1, 仅包含数字, 字母, 下划线时会被缓存. 如果包含其他字符, 而长度<=1 也会被驻存,
②. 乘数大于1 . 仅包含数字, 字母, 下划 线这个时候会被缓存. 但字符串长度不能大于20
d. 指定驻留留. 我们可以通过sys模块中的intern()函数来指定要驻留留的内容.
>>> from sys import intern
>>> a = intern('alex.sb.com' * 10)
>>> b = intern('alex.sb.com' * 10)
>>> a is b
True
3. py文件与command小数据池区别
在代码块内的缓存机制是不一样的. 在执行同一个代码块的初始化对象的命令时, 会检查其值是否已经存在, 如果存在, 会将其重用. 换句话说: 执行同一个代码块时, 遇到初始 化对象的命令时,他会将初始化的这个变量与 值存储在一个字典中, 在遇到新的变量时, 会先在字典中查询记录, 如果有同样的记录那么它会重复使用这个字典中的之前的这个值. 所以在 你给出的例子中, 文件执行时(同一个代码块) 会把a, b两个变量指向同一个对象. 如 果是不同的代码块, 他就会看这个两个变量是否是满足小数据池的数据, 如果是满足小数据池的数据则会指向同一个地址. 所以: a, b的赋值语句分别被当作两个代码块执行, 但是他们不满足小数据池的数据所以会得到两个不同的对象, 因而is判断返回False.
py文件里. 一个代码块内部. 只会缓存int, str, bool 也有自己的小数据池。 缓存的范围会比外面的代码块的数据池要大
(1). 数字。都会缓存。 运算的结果不缓存(-5~256 会缓存)
(2). 字符串。 默认的字符串都缓存. 如果有乘法。 遵循上方的结论
(3). 布尔值。 默认缓存
4. is 和 == 区别
查看内存地址:id(变量)
is : 判断左右两端内容的内存地址是否一致. 如果返回True, 那可以确定这两个变量量使 用的是同一个对象
== :判断左右两端的值是否相等. 是不是一致.
二、编码
1. python2和python编码
(1) python2 - ASCII
默认使用ASCII码,所以不支持中文. 如果需要在Python2中更改编码. 需要在文件的开始编写。
# -- encoding:utf-8 -
(2) python3 - UTF-8
(1)ASCII : 最早的编码.里面有英文大写字母,小写字母,数字,一些特殊字符.没有中文,8个01代码,8b,1B (2)GBK: 中文国标码,里面包含了ASCII编码和中文常用编码.16b, 2B
(3)UNICODE: 万国码, 里面包含了全世界所有国家文字的编码. 32b, 4B, 包含了了 ASCII
(4)UTF-8: 可变长度的万国码.是unicode的一种实现.最⼩字符占8位;
英文8b,1B 欧文16b,2B 中文24bit,3B
综上, 除了了ASCII码以外, 其他信息不能直接转换.
2. 编解码
在python3的内存中。 在程序运⾏阶段。 使用的是unicode编码。 因为unicode是万国码。 什么内容都可以进行显示。 那么在数据传输和存储的时候由于unicode比较浪费空间和资源。 需要把 unicode转存成UTF-8或者GBK 进行存储。 怎么转换呢。 在python中可以把文字信息进行编码。 编码之后的内容就可以进行传输了。 编码之后的数据是bytes类型的数据。其实啊。 还是原来的数据只是经过编码之后表现形式发生了改变而已。
bytes的表现形式: (1)英⽂ b'alex' 英⽂的表现形式和字符串没什么两样 (2)中文 b'\xe4\xb8\xad' 这是一个汉字的UTF-8的bytes表现形式
(1) 举例
s = "alex"
print(s.encode("utf-8")) # 将字符串串编码成UTF-8
print(s.encode("GBK")) # 将字符串串编码成GBK
结果:
b'alex'
b'alex'
s = "中"
print(s.encode("UTF-8")) # 中?文编码成UTF-8
print(s.encode("GBK")) # 中?文编码成GBK
结果:
b'\xe4\xb8\xad'
b'\xd6\xd0
备注:英⽂编码之后的结果和源字符串一致.中文编码之后的结果根据编码的不同. 编码结果也不同. 我们能看到. 一个中文的UTF-8编码是3个字节. 一个GBK的中文编码是2个字节. 编码之后的类型就是bytes类型.在网络传输和存储的时候我们python是保存和存储的bytes 类型. 那么在对方接收的时候. 也是接收的bytes类型的数据. 我们可以使用decode()来进行解码操作. 把bytes类型的数据还原回我们熟悉的字符串
s = "我叫李李嘉诚"
print(s.encode("utf-8"))
# b'\xe6\x88\x91\xe5\x8f\xab\xe6\x9d\x8e\xe5\x98\x89\xe8\xaf\x9a'
# 解码
print(b'\xe6\x88\x91\xe5\x8f\xab\xe6\x9d\x8e\xe5\x98\x89\xe8\xaf\x9a'.decod e("utf-8"))
s = "我是文字"
bs = s.encode("GBK") # 我们这样可以获取到GBK的文字
# 把GBK转换成UTF-8
# 首先要把GBK转换成unicode. 也就是需要解码
s = bs.decode("GBK") # 解码
# 然后需要进行重新编码成UTF-8
bss = s.encode("UTF-8") # 重新编码
print(bss)
三、文件操作
1. 初始文件操作
使用python来读写文件时非常简单的操作。我们使用open()函数来打开一个文件,获取文件句柄,然后通过文件句柄就可以进行各种文件操作。打开文件需要close()文件。可使用with上下文进行操作文件。
2. 文件操作模式
文件操作流程:建立文件对象,调用文件方法进行操作,不要忘记关闭文件(文件不关闭的情况下,内容会放在缓存,虽然python会在最后自动把内容读到磁盘)
(1) r(only-read)
f = open("file", "r")
# read逐个字符地全部读取出,read可以指定参数,设定要读取多少字符;无论一个英文字母还是一个汉字都是一个字符
f_read = f.read()
f = open('file1','r')
# readlines会把内容以列表的形式输出
f_read = f.readlines()
print(f_read)
f.close()
# 推荐读取方式
#输出一行内容输出一个空行,一行内容一行空格... 因为文件中每行内容后面都有一个换行符,而且print()语句本身就可以换行,如果不想输出空行,就需要使用下面的语句:print(line.strip())
f = open('file1','r')
for line in f.readlines()
print(line)
f.close()
# 读取图片、视频流文件 - rb
f = open('file', rb)
(2) w(only-write)
在进行操作前,文件中所有内容会被清空。由于Python3的默认编码方式是Unicode,所以在写入文件的时候需要调用utf8,以utf8的方式保存,这时pycharm(默认编码方式是utf8)才能正确读取,当读取文件时,文件是utf8格式,pycharm也是utf8,就不需要调用了。写入字节文件wb
f = open('file1','w',encoding='utf8')
f_w = f.write('hello world')
#有意思的是,这里并不打印'hello world',只打印写入多少字符
print(f_w)
f.close()
(3) a(append)
与w模式不同的是,a模式不会把原来内容清空,而是光标移到内容最后位置,继续写入新内容。比如在最后追加'hello world'
f = open('file1','a')
f_a = f.write('hello world')
#还是会打印写入的字符数
print(f_a)
f.close()
(4) 读取大文件
num = 0
# 不要过早关闭文件,否则程序不能识别操作句柄f.
f.close()
f = open('file','r')
# for内部把f变为一个迭代器,用一行取一行
for i in f:
num += 1
if num == 5:
i = ''.join([i.strip(),'hello world'])
print(i.strip())
f.close()
3. 其他操作
(1) tell 和 seek
f = open('file','r')
print(f.tell()) #光标默认在起始位置
f.seek(10) #把光标定位到第10个字符之后
print(f.tell()) #输出10
f.close()
----------------------
f = open('file','w')
print(f.tell()) #先清空内容,光标回到0位置
f.seek(10)
print(f.tell())
f.close()
----------------------
f = open('file','a')
print(f.tell()) #光标默认在最后位置
f.write('你好 世界')
print(f.tell()) #光标向后9个字符,仍在最后位置
f.close()
(2) flush
同步将数据从缓存转移到磁盘; 如实现进度条
import sys,time #导入sys和time模块
for i in range(40):
sys.stdout.write('*')
# flush的作用相当于照相,拍一张冲洗一张
sys.stdout.flush()
time.sleep(0.2)
# 下面代码也能够实现相同的功能
import time
for i in range(40):
# print中的flush参数
print('*',end='',flush=True)
time.sleep(0.2)
(3) truncate - 截断
不能是r模式下执行,w模式下,已经清空所有数据,使用truncate
没有任何意义,a模式下,截断指定位置后的内容。
f = open('file','a')
# 只显示6个字节的内容(6个英文字符或三个汉字),后面的内容被清空
f.truncate(6)
(4) 光标位置总结
#--------------------------光标总结head-----------------------------------
f = open('file','r')
print(f.read(6)) #6个字符
print(f.tell()) #位置12字节,一个汉字两个字节
f.close()
f = open('file','r')
f.seek(6) #6个字节
print(f.tell())
f.close()
f = open('file','a')
# 光标默认在最后位置
print(f.tell())
f.write('你好 世界')
# 光标向后9个字节,一个汉字两个字节,仍在最后位置 182-->191
print(f.tell())
f.close()
f = open('file','a',encoding='utf-8')
# 由于需要光标定位位置,所以也是字节。只显示6个字节的内容(6个英文字母或三个汉字,一个汉字两个字节),后面的内容被清空。
print(f.truncate(6))
f.close()
(4) r+/w+/a+
r+:读写模式,光标默认在起始位置,当需要写入的时候,光标自动移到最后
w+:写读模式,先清空原内容,再写入,也能够读取
a+:追加读模式,光标默认在最后位置,直接写入,也能够读取。
f = open('file','a')
print(f.tell()) #末尾207位置
f.close()
f = open('file','r+')
print(f.tell()) #0位置
print(f.readline()) #读取第一行
f.write('羊小羚') #光标移到末尾207位置并写入
print(f.tell()) #213位置
f.seek(0) #光标移到0位置
print(f.readline()) #读取第一行
f.close()
(5) 修改文件内容
由于数据存储机制的关系,我们只能把文件1中的内容读取出来,经过修改后,放到文件2中
f2 = open('file2','w',encoding='utf8') #写入的时候必须加utf8
f1 = open('file','r')
num = 0
for line in f1: #迭代器
num += 1
if num == 5:
line = ''.join([line.strip(),'羊小羚\n']) #里面就是对字符串进行操作了
f2.write(line)
f1.close()
f2.close()
4. with语句
可以同时对多个文件同时操作,当with
代码块执行完毕时,会自动关闭文件释放内存资源,不用特意加f.close()
,我们通过下面的示例体会with
的用法和好处。用with
语句重写8中的代码
num = 0
with open('file','r') as f1,open('file2','w',encoding='utf8') as f2:
for line in f1:
num += 1
if num == 5:
line = ''.join([line.strip(),'羊小羚'])
f2.write(line)