(第四集)数据类型-字符编码-文件处理

一 引子


数据类型

数字(整形,长整形,浮点型,复数)
字符串
字节串:在介绍字符编码时介绍字节bytes类型
列表
元组
字典
集合

二 数字


整型int

作用:年纪,等级,身份证号,qq号等整型数字相关
定义:age=10 #本质age=int(10)

浮点型float

作用:薪资,身高,体重,体质参数等浮点数相关
salary=3000.3 #本质salary=float(3000.3

其他数字类型

  • 长整形:
在python2中(python3中没有长整形的概念):      
    >>> num=2L
    >>> type(num)
  • 复数:
 >>> x=1-2j
    >>> x.real
    1.0
    >>> x.imag
    -2.0  

三 字符串


#作用:名字,性别,国籍,地址等描述信息
#定义:在单引号\双引号\三引号内,由一串字符组成
name='egon'
#优先掌握的操作:
#1、按索引取值(正向取+反向取) :只能取
#2、切片(顾头不顾尾,步长)
#3、长度len
#4、成员运算in和not in
#5、移除空白strip
#6、切分split
#7、循环

四 列表


#ps:反向步长
l=[1,2,3,4,5,6]
#正向步长
l[0:3:1] #[1, 2, 3]
#反向步长
l[2::-1] #[3, 2, 1]
#列表翻转
l[::-1] #[6, 5, 4, 3, 2, 1]
#作用:多个装备,多个爱好,多门课程,多个女朋友等
#定义:[]内可以有多个任意类型的值,逗号分隔
my_girl_friends=['alex','wupeiqi','yuanhao',4,5] #本质my_girl_friends=list([...])
或
l=list('abc')
#优先掌握的操作:
#1、按索引存取值(正向存取+反向存取):即可存也可以取      
#2、切片(顾头不顾尾,步长)
#3、长度
#4、成员运算in和not in
#5、追加
#6、删除
#7、循环

五 元组


#作用:存多个值,对比列表来说,元组不可变(是可以当做字典的key的),主要是用来读
#定义:与列表类型比,只不过[]换成()
age=(11,22,33,44,55)本质age=tuple((11,22,33,44,55))

#优先掌握的操作:
#1、按索引取值(正向取+反向取):只能取   
#2、切片(顾头不顾尾,步长)
#3、长度
#4、成员运算in和not in
#5、循环

六 字典


#作用:存多个值,key-value存取,取值速度快

#定义:key必须是不可变类型,value可以是任意类型
info={'name':'egon','age':18,'sex':'male'} #本质info=dict({....})
或
info=dict(name='egon',age=18,sex='male')
或
info=dict([['name','egon'],('age',18)])
或
{}.fromkeys(('name','age','sex'),None)

#优先掌握的操作:
#1、按key存取值:可存可取
#2、长度len
#3、成员运算in和not in

#4、删除
#5、键keys(),值values(),键值对items()
#6、循环

七 集合


#作用:去重,关系运算
#定义集合:
            集合:可以包含多个元素,用逗号分割,
            集合的元素遵循三个原则:
             1:每个元素必须是不可变类型(可hash,可作为字典的key)
             2:没有重复的元素
             3:无序

七 集合


#作用:去重,关系运算
#定义集合:
            集合:可以包含多个元素,用逗号分割,
            集合的元素遵循三个原则:
             1:每个元素必须是不可变类型(可hash,可作为字典的key)
             2:没有重复的元素
             3:无序
#1、长度len
#2、成员运算in和not in
#3、|合集
#4、&交集
#5、-差集
#6、^对称差集
#7、==
#8、父集:>,>= 
#9、子集:<,<=   

# 有如下两个集合,pythons是报名python课程的学员名字集合,linuxs是报名linux课程的学员名字集合
pythons={'alex','egon','yuanhao','wupeiqi','gangdan','biubiu'}
linuxs={'wupeiqi','oldboy','gangdan'}
# 求出即报名python又报名linux课程的学员名字集合
print(pythons & linuxs)
# 求出所有报名的学生名字集合
print(pythons | linuxs)
# 求出只报名python课程的学员名字
print(pythons - linuxs)
# 求出没有同时这两门课程的学员名字集合
print(pythons ^ linuxs)

去重

去重,无需保持原来的顺序
l=['a','b',1,'a','a']
print(set(l))
l=[1,'a','b',1,'a']
方法一:不用集合
l1=[]
for i in l:
    if i not in l1:
        l1.append(i)
print(l1)

#方法二:借助集合
l1=[]
s=set()
for i in l:
    if i not in s:
        s.add(i)
        l1.append(i)
print(l1)
#同上方法二,去除文件中重复的行
import os
with open('db.txt','r',encoding='utf-8') as read_f,
        open('.db.txt.swap','w',encoding='utf-8') as write_f:
    s=set()
    for line in read_f:
        if line not in s:
            s.add(line)
            write_f.write(line)
os.remove('db.txt')
os.rename('.db.txt.swap','db.txt')

八 数据类型总结


按存储空间的占用分(从低到高):

数字
字符串
集合:无序,即无序存索引相关信息
元组:有序,需要存索引相关信息,不可变
列表:有序,需要存索引相关信息,可变,需要处理数据的增删改
字典:无序,需要存key与value映射的相关信息,可变,需要处理数据的增删改

按存值个数区分

:数字,字符串
标量/原子类型

容器类型:列表,元组,字典

按可变不可变区分

可变:列表,字典
不可变:数字,字符串,元组

按访问顺序区分:

直接访问:数字
顺序访问(序列类型):字符串,列表,元组
key值访问(映射类型):字典

九 运算符


身份运算(isis notis比较的是内存中的id,而双等号比较的是值
毫无疑问,id若相同则值肯定相同,而值相同id则不一定相同
>>> x=1234567890
>>> y=1234567890
>>> x == y
True
>>> id(x),id(y)
(3581040, 31550448)
>>> x is y
False

十 字符编码


文本编辑器存取文件的原理:编辑器编写的内容存放与内存中。

python解释器执行py文件的原理:

python解释器启动。硬盘上将test.py的文件内容读入到内存中。python解释器解释执行刚刚加载到内存中test.py的代码。

python解释器与文件本编辑的异同

  • 相同点:

    python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样。

  • 不同点:

    文本编辑器将文件内容读入内存后,是为了显示或者编辑,不理会python的语法。
    python解释器将文件内容读入内存后,是为了执行python代码、会识别python语法。

字符编码介绍

什么是字符编码:计算机只认识数字:字符——–(翻译过程)——->数字 ,一个字符如何对应一个特定数字的标准,这个标准称之为字符编码。

  • 以下两个场景下涉及到字符编码的问题:
    一个python文件中的内容是由一堆字符组成的,存取均涉及到字符编码问题。
    python中的数据类型字符串是由一串字符组成的(python文件执行时,即第三个阶段)。

  • 字符编码的发展的三个阶段:
    1.现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII。1个Bytes代表一个字符。
    2.为了满足中文和英文,中国人定制了GBK,2Bytes代表一个中文字符,1Bytes表示一个英文字符。
    3.能够兼容万国字符,与全世界所有的字符编码都有映射关系,可转换成任意国家的字符编码。unicode(定长),用2Bytes代表一个字符,UTF-8(可变长),英文字符用1Bytes表示,中文字符用3Bytes。

总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。

字符编码应用之文件编辑器

  • 乱码分析:
乱码一:存文件时就已经乱码。
存文件时,由于文件内有各个国家的文字,单以shiftjis去存,
本质上其他国家的文字由于在shiftjis中没有找到对应关系而导致存储失败。即存文件阶段就已经发生乱码
而当我们用shiftjis打开文件时,日文可以正常显示,而中文则乱码
乱码二:存文件时不乱码而读文件时乱码。
存文件时用utf-8编码,保证兼容万国,不会乱码,而读文件时选择了错误的解码方式,
比如gbk,则在读阶段发生乱码,读阶段发生乱码是可以解决的,选对正确的解码方式就ok

文本编辑器之python解释器

文件test.py以gbk格式保存,内容为:
  x='林'
无论是python2 test.py
还是python3 test.py
都会报错(因为python2默认ascii,python3默认utf-8)
除非在文件开头指定#coding:gbk

总结

保证不乱码的核心就是符按照什么标准而编码的,就按照什么标准解码,此处的标准指的就是字符编码。

在内存中写的所有字符都是unicode编码,比如我们打开编辑器,输入一个“你”,我们并不能说“你”就是一个汉字,
此时它仅仅只是一个符号,该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样。
只有在我们往硬盘保存或者基于网络传输时,才能确定”你“到底是一个汉字,还是一个日本字,
这就是unicode转换成其他编码格式的过程。

保存文件流程:unicode(内存,属于字符)----->encode-------->utf-8(硬盘,属于字节)
读取文件:utf-8-------->decode---------->unicode

补充:浏览网页时,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器。服务端encode的编码格式是utf-8, 客户端内存中收到的也是utf-8编码的结果

字符编码应用之python

执行python程序的三个阶段 :

阶段一:启动python解释器
阶段二:python解释器此时就是一个文本编辑器,负责打开文件test.py,即从硬盘中读取test.py的内容到内存中,#coding:utf-8,决定以什么编码格式来读入内存。
阶段三:读取已经加载到内存的代码(unicode编码格式),然后执行。执行过程中可能会开辟新的内存空间,比如x="egon"

python2与python3字符串类型的区别


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

  • str类型:
#coding:gbk
x='上'
y='下'
print([x,y]) #['\xc9\xcf', '\xcf\xc2']
#\x代表16进制,此处是c9cf总共4位16进制数,一个16进制四4个比特位,
416进制数则是16个比特位,即2个Bytes,这就证明了按照gbk编码中文用2Bytes
print(type(x),type(y)) 
#(<type 'str'>, <type 'str'>)
#print()会自动转换编码

理解字符编码:gbk存中文需要2个bytes,存英文则需要1个bytes。

  • unicode类型:
python解释器执行到产生字符串的代码时(例如s=u'林'),会申请新的内存地址,
然后将'林'以unicode的格式存放到新的内存空间中,所以s只能encode,不能decode。
#数据encode后是字节类型,通过print()函数自动编码成字符串类型显示
#coding:gbk
x=u'上' #等同于 x='上'.decode('gbk')
y=u'下' #等同于 y='下'.decode('gbk')
print([x,y]) #[u'\u4e0a', u'\u4e0b']

print(type(x),type(y))
 #(, )
  • 打印到终端:
x='上'    #gbk中,字符串存放为\xc9\xcf
在print(x)时,使用终端的编码格式,将内存中的\xc9\xcf转成字符显示,此时就需要终端编码必须为gbk,否则无法正常显示原内容。
对于unicode格式的数据来说,无论怎么打印,都不会乱码。

python2中存储的是str类型,不是unicode,需要手动在数据前面添加u来转换成Unicode类型,从而解决乱码的问题。
在python3中将str直接存成unicode,我们定义一个str,无需加u前缀,就是一个unicode

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

str是unicode:

#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类型

十一 文件处理


文件操作

文件是操作系统提供给应用程序来操作硬盘虚拟概念,

#1. 打开文件,得到文件句柄并赋值给一个变量
f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r
#2. 通过句柄对文件进行操作
data=f.read()
#3. 关闭文件
f.close()
f=open('a.txt','r')的过程分析:
#1、由应用程序向操作系统发起系统调用open(...)
#2、操作系统打开该文件,并返回一个文件句柄给应用程序
#3、应用程序将文件句柄赋值给变量f

强调

  • 回收机制:
在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收。
f.close() #回收操作系统级打开的文件
del f #回收应用程序级的变量
使用with关键字来管理上下文:
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
    data=read_f.read()
    write_f.write(data)
  • 字符编码
操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8
可以指定字符编码格式:
f=open('a.txt','r',encoding='utf-8')

打开文件的模式

文件句柄 = open(‘文件路径’, ‘模式’)

#1. 打开文件的模式有(默认为文本模式):
r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a, 只追加写模式【不可读;不存在则创建;存在则只追加内容】
 对于非文本文件,使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb 
wb
ab
"+" 表示可以同时读写某个文件
r+, 读写【可读,可写】
w+,写读【可读,可写】
a+, 写读【可读,可写】

操作文件的方法

f.read() #读取所有内容,光标移动到文件末尾
f.readline() #读取一行内容,光标移动到第二行首部
f.readlines() #读取每一行内容,存放于列表中

f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n']) #文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
f.readable() #文件是否可读
f.writable() #文件是否可写
f.closed #文件是否关闭
f.encoding #如果文件打开模式为b,则没有该属性
f.flush() #立刻将文件内容从内存刷到硬盘
f.name

利用b模式,编写一个cp工具

import sys
if len(sys.argv) != 3:
    print('usage: cp source_file target_file')
    sys.exit()

source_file,target_file=sys.argv[1],sys.argv[2]
with open(source_file,'rb') as read_f,open(target_file,'wb') as write_f:
    for line in read_f:
        write_f.write(line)

文件内光标移动

read(3):
代表读取3个字符/3个字节

import time
with open('test.txt','rb') as f:
    f.seek(0,2)   # 从文档最开始位置,往后移动2个字符
    while True:
        line=f.readline()
        if line:
            print(line.decode('utf-8'))
        else:
            time.sleep(0.2)

文件的修改

方式一:
将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘

import os
with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    data=read_f.read() #全部读入内存,如果文件很大,会很卡
    data=data.replace('alex','SB') #在内存中完成修改
    write_f.write(data) #一次性写入新文件
os.remove('a.txt')
os.rename('.a.txt.swap','a.txt') 

方式二:(推荐,不占用太多资源)
将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件。

import os
with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    for line in read_f:
        line=line.replace('alex','SB')
        write_f.write(line)
os.remove('a.txt')
os.rename('.a.txt.swap','a.txt') 

你可能感兴趣的:(python大神进化记,数据类型-字符编码-文件处理)