python进阶与文件处理(数据类型分类,python深浅拷贝,异常处理,字符编码,基本文件操作,绝对路径和相对路径,,高级文件操作,文件的修改)

数据类型分类

按存值个数区分

单个值:数字,字符串

多个值(容器):列表,元组,字典,集合

按可变不可变区分

可变:列表,字典,集合

不可变:数字,字符串,元组

有序无序区分

有序(可按索引取值):字符串,列表,元组

无序:字典,集合

Python深浅拷贝

拷贝:

当lt2为lt的拷贝对象时,lt内的可变类型变化,lt2变化;lt内的不可变类型变化,lt2变化。(简单的赋值)

浅拷贝:

当lt2为lt的浅拷贝对象时,lt内的可变类型变化,lt2变化;lt内的不可变类型变化,lt2不变化。【copy.copy() 可变数据的类型中的内置方法.copy模块】

深拷贝:

当lt2为lt的深拷贝对象时,lt内的可变类型变化,lt2不变化;lt内的不可变类型变化,lt2不变。【copy.deepcopy()】

牢记:

拷贝/浅拷贝/深拷贝 只针对可变数据类型

异常处理

异常是什么?

异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止)

一般异常有语法错误逻辑错误

为什么要异常处理

为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理

①如果错误发生的条件是可预知的,我们可以用if进行处理:在错误发生之前进行预防

②如果错误发生的条件是不可预知的,则需要用到try...except:在错误发生之后进行处理

#基本语法为
try:
    被检测的代码块
except 异常类型:
    try中一旦检测到异常,就执行这个位置的逻辑

在try...except中如果你想要的效果是,无论出现什么异常类型,我们统一丢弃,或者使用同一段代码逻辑去处理他们,那么就可以使用万能异常Exception

s1 = 'hello'
try:
    int(s1)
except Exception as e:
    print(e)

异常的最终执行

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)
#except Exception as e:
#    print(e)
else:
    print('try内代码块没有异常则执行我')
finally:
    print('无论异常与否,都会执行该模块,通常是进行清理工作')

try...except总结

  1. 把错误处理和真正的工作分开来
  2. 代码更易组织,更清晰,复杂的工作任务更容易实现;
  3. 毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了;

注意

  1. 语法错误无法用try...except捕捉
  2. 逻辑错误可以用try...except捕捉

了解其他异常处理方法

抛出异常raise(一般用来自定义异常)

class EgonException(BaseException):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg


try:
    raise EgonException('抛出异常,类型错误')
except EgonException as e:
    print(e)

断言assert

try:
    assert 1 == 2
except Exception as e:
    print(e)

字符编码

什么是字符编码

在计算机内部,所有信息都是由一个个二进制值组成,每一个二进制(bit),有0和1两种状态,因此,8个二进制位可以组合出256种状态,这种称为字节(byte).

字符编码是将人类的字符编码成计算机能识别的数字.这种转换必须遵循一套固定的标准,该标准无非是人类字符与数字的对应关系,称之为字符编码表。

字节码与机器码的区别:

字节码是一种中间状态(中间码)的二进制代码(文件).需要直译器转译后才能成为机器码

ascii:

上世界60年代,美国制定了一套字符编码,对英文字符与二进制之间做了联系,这被称为ASCII码,一直沿用至今,ascii码一共规定了128个字符(早期编码,只支持英文字母和一些符号)

unicode:

这是一种所有符号的编码,主要作用因为世界上有多种编码方法,同一个二进制数字可以被解释成不同的符号.导致打开一个文本文件时必须用其对应的编码格式,否则会出现乱码.所以就有了unicode诞生.(万国码,能表示多种符号,在PYthon2中可以指定4字节或2字节表示一个字符,PYthon3中默认4字节)

utf-8:

最大的特点就是,它是一种变长编码,可以使用1-4个字节表示一个符号,根据不同的符号来变化字节的长度.(用最短的方式表示unicode,一个英文字符占一字节)

Gbk:

中文编码。

内存为什么不用UTF-8呢?

出现这个问题的原因是硬盘中还躺了其他国家的代码,各个国家的代码的二进制还需要运行在计算机上使用,因此内存中必须使用Unicode的编码,因为Unicode能和硬盘中其他国家的二进制中的代码进行转换,但是UTF-8只是简化了代码的存储,它并不能与其他国家硬盘中的代码进行关系转换。总而言之只有Unicode编码才能运行其他国家硬盘中的代码,而UTF-8的代码无法进行该操作。

内存中还使用Unicode编码,是因为历史遗留问题造成的,但是因为现在写代码使用的都是UTF-8代码,所以以后内存中的代码都将变成UTF-8代码,并且以前遗留的各个国家的代码都将被淘汰,所以未来内存中使用的编码也将使用UTF-8编码替代Unicode编码。

总结:

  1. 保证不乱码的核心法则就是,字符按照什么标准而编码的,就要按照什么标准解码,此处的标准指的就是字符编码。
  2. 在内存中写的所有字符,一视同仁,都是Unicode编码,比如我们打开编辑器,输入一个“你”,我们并不能说“你”就是一个汉字,此时它仅仅只是一个符号,该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样。只有在我们往硬盘保存或者基于网络传输时,才能确定”你“到底是一个汉字,还是一个日本字,这就是Unicode转换成其他编码格式的过程了。简而言之,就是内存中固定使用的就是Uncidoe编码,我们唯一能改变的就是存储到硬盘时使用的编码。
  • Unicode----->encode(编码)-------->gbk
  • Unicode<--------decode(解码)<----------gbk

基本的文件操作

打开文件的流程

如果我们需要打开一个文件,需要向操作系统发起请求,要求操作系统打开文件,占用操作系统资源。Python中使用open()方法可以打开某个具体的文件,open()方法内写入文件路径。

# 打开文件
f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt')
print(f)
# read模式打开文件
f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt', mode='r')
# 读取文件内容,向操作系统发起读请求,会被操作系统转成具体的硬盘操作,将内容由硬盘读入内存
data = f.read()
print(data)
# 由于Python的垃圾回收机制只回收引用计数为0的变量,但是打开文件还占用操作系统的资源,所以我们需要回收操作系统的资源资源
# del f 只是回收变量f
f.close()
# write模式打开文件
f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt', mode='w')
f.write("""name = 'nick'
pwd = '123'""")
f.close()
f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt', mode='r')
data = f.read()
print(data)

绝对路径和相对路径

绝对路径:从盘符(C:、D:)开始写一个完整的路径。

相对路径:相对于当前执行文件所在的文件夹开始找。

文件的三种打开模式

文件操作的基础模式有三种(默认的操作模式为r模式):

  • r模式为read(只读模式,只能读不能写,文件不存在时报错。)

    # rt: read by text
    # windows的操作系统默认编码为gbk,因此需要使用utf8编码
    f = open('32.txt', mode='rt', encoding='utf8')
    data = f.read()
    print(data)
    print(f"type(data): {type(data)}")
    f.close()
    

    由于f.read()一次性读取文件的所有内容,如果文件非常大的话,可能会造成内存爆掉,即电脑卡死。因此可以使用f.readline()/f.readlines()读取文件内容。

    # f.readline()/f.readlines()
    f = open('32.txt', mode='rt', encoding='utf8')
    print(f"f.readable(): {f.readable()}")  # 判断文件是否可读
    data1 = f.readline()
    data2 = f.readlines()
    print(f"data1: {data1}")
    print(f"data2: {data2}")
    f.close()
    
  • w模式为write(只能写,不能读,文件存在的时候回清空文件后再写入内容;文件不存在的时候会创建文件后写入内容。)

    # wt
    f = open('34w.txt', mode='wt', encoding='utf8')
    print(f"f.readable(): {f.readable()}")
    f.write('nick 真帅呀
    ')  # '
    '是换行符
    f.write('nick,nick, you drop, I drop.')
    f.write('nick 帅的我五体投地')
    f.flush()  # 立刻将文件内容从内存刷到硬盘
    f.close()
    
  • a模式为append(可以追加。文件存在,则在文件的末端写入内容;文件不存在的时候会创建文件后写入内容。)

    # at
    f = open('34a.txt', mode='at', encoding='utf8')
    print(f"f.readable(): {f.readable()}")
    f.write('nick 真帅呀
    ')  # '
    '是换行符
    f.write('nick,nick, you drop, I drop.')
    f.write('nick 帅的我五体投地')
    f.close()
    

文件读写内容的格式有两种(默认的读写内容的模式为b模式):

  • t模式为text
  • b模式为bytes(b模式是通用的模式,因为所有的文件在硬盘中都是以二进制的形式存储的,需要注意的是:b模式读写文件,一定不能加上encoding参数,因为二进制无法再编码。)

需要注意的是:t、b这两种模式均不能单独使用,都需要与r/w/a之一连用。

with管理文件操作上下文

之前我们使用open()方法操作文件,但是open打开文件后我们还需要手动释放文件对操作系统的占用。但是其实我们可以更方便的打开文件,即Python提供的上下文管理工具——with open()。

with open('32.txt', 'rt', encoding='utf8') as f:
    print(f.read())

with open()方法不仅提供自动释放操作系统占用的方法,并且with open可以使用逗号分隔,一次性打开多个文件,实现文件的快速拷贝。

Copywith open('32.txt', 'rb') as fr, 
        open('35r.txt', 'wb') as fw:
    f.write(f.read())

文件的高级应用

可读、可写

  • r+t: 可读、可写
  • w+t: 可写、可读
  • a+t: 可追加、可读

修改文件的两种方式

方式一

将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)。

import os

with open('37r.txt') as fr, 
        open('37r_swap.txt', 'w') as fw:
    data = fr.read()  # 全部读入内存,如果文件很大,会很卡
    data = data.replace('tank', 'tankSB')  # 在内存中完成修改

    fw.write(data)  # 新文件一次性写入原文件内容

# 删除原文件
os.remove('37r.txt')
# 重命名新文件名为原文件名
os.rename('37r_swap.txt', '37r.txt')

方式二

将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件。

import os

with open('37r.txt') as fr,
        open('37r_swap.txt', 'w') as fw:
    # 循环读取文件内容,逐行修改
    for line in fr:
        line = line.replace('jason', 'jasonSB')
        # 新文件写入原文件修改后内容
        fw.write(line)

os.remove('37r.txt')
os.rename('37r_swap.txt', '37r.txt')

总而言之,修改文件内容的思路为:以读的方式打开原文件,以写的方式打开一个新的文件,把原文件的内容进行修改,然后写入新文件,之后利用os模块的方法,把原文件删除,重命名新文件为原文件名,达到以假乱真的目的。

原文地址:https://www.cnblogs.com/asyouwish/p/11312149.html