Python测开28期 - 旎奥 - 学习笔记 - python高级语法:文件操作、异常处理

文件操作

文件操作是每一门编程语言中都必不可少的一项语法,通过文件,可以实现数据持久化存储,测试数据驱动文件的处理,程序配置文件的处理等。

在程序中操作文件和使用图形界面操作文件的过程基本一致,都要进行找到文件位置,打开文件,读写文件,关闭文件等操作。

打开文件

Python 使用 open 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。

完整格式:

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

简化格式:

open(file, mode='r', encoding=None)
  • file: 必需,指定打开文件的路径(相对或者绝对路径)。
  • mode: 可选,文件打开模式,默认为r只读模式
  • encoding: 一般使用 utf8

mode参数常见下表:

字符 含意
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
w 以只写方式打开文件。如果该文件已存在则覆盖文件。如果该文件不存在则创建新文件。
a 以追加写入方式打开文件,如果文件存在则在末尾追加,文件不存在则创建新文件
b 二进制模式
t 文本模式(默认)
# 以写入文件打开 index.html 文件
file = open("index.html", "w")

文件关闭

文件在操作完以后,需要将其关闭,close() 方法用于关闭一个已打开的文件。

关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。

close() 方法允许调用多次。

使用 close() 方法关闭文件是一个好的习惯。

格式:fileObject.close()

# 以写入文件打开 index.html 文件
file = open("index.html", "w")
# 关闭文件
file.close()

文件写入

write() 方法

write() 方法用于向文件中写入指定字符串。如果文件打开模式为b,则要将字符串转换成 bytes类型的二进制字符串,函数返回成功写入数据的长度。

格式:fileObject.write( [ str ])

# 以写入文件打开 index.html 文件
file = open("index.html", "w")
# 写入数据
file.write("<h1>文件写入标题</h1>")
file.write("\n")
file.write("<p>文件写入内容。。。。。。</p>")
# 关闭文件
file.close()

writelines() 方法

writelines() 方法用于向文件中写入一序列的字符串。

这一序列字符串可以是由迭代对象产生的,如一个字符串列表。

注意:不要被方法名所迷惑,如果每个元素独占一行,需要在数据后指定换行符 \n

格式:fileObject.writelines(seq)

datas = ["AAAAAAAAAAAA\n","BBBBBBBBBBBB\n","CCCCCCCCCCCC\n","DDDDDDDDDDDD\n"]
file = open('data.txt',"w")
file.writelines(datas)
file.close()

读取文件

read() 方法

read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有。

格式:fileObject.read([size=-1])

file = open('data.txt',"r")
# 读取10个字符
content = file.read(10)
print(content)
# 读取所有内容
content = file.read()
print(content)
file.close()

readline() 方法

readline() 方法用于从文件读取整行,包括 \n 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 \n 字符。

格式:fileObject.readline(size=-1)

file = open('data.txt',"r")
# 读取10个字符
content = file.readline(10)
print(content)
# 读取文件指针所在行剩余所有内容
content = file.readline()
print(content)
file.close()

readlines()方法

readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表。

格式:fileObject.readlines()

file = open('data.txt',"r")
# 以行为单位读取文件所有的内容
contents = file.readlines()
print(contents)
file.close()

调试与分析

在编写程序过程中,出现错误是再所难免的,出现错误后,如何能通过报错信息,快速找出并修复错误,是代码开发过程中非常重要的技能。

错误分析

程序出现错误并中断结束后,出现报错信息的错误都是不可怕的,大多都是一些语法性的错误,通过错误提示信息,就可以快速定位和解决错误。

错误分析:

  1. 错误所在的文件
  2. 错误所在的行
  3. 错误出现的代码
  4. 错误类型
  5. 错误原因描述

有时候通过报错信息,并不能直接定位出错误,要通过报错信息,及程序的上下文逻辑来分析真正的报错原因。

在上面的错误中,共提示了两处报错位置,分别是12行和7行,这是代码追踪提示。

但真正的错误并不在这里,通过错误原因描述发现,是在执行range()函数时,并不能将字符串类型的参数解释成一个数字。

从代码实现逻辑上看,output 函数并没有任何问题,结合上下文的代码逻辑发现,问题出在 getInputData 函数中的数据获取,从键盘输入的所有内容都是以字符串形式保存到程序变量中,程序要求获得一个数字,那么在键盘输入后,应该使用强制类型转换,将输入数据转换成数字。

n = input("请输入一个数字:")修改为n = int(input("请输入一个数字:"))

print信息调试

很多人由于英文不太好,在查看报错信息时很吃力,也可以通过 print() 函数,自行输出信息来定位错误位置,虽然这种方式可以解决问题,但还是要慢慢学习,掌握如何查看报错提示。

示例代码:

def getInputData():
    print("input run")
    n = input("请输入一个数字:")
    msg = input("请输入一个数据:")
    return n,msg

def outputData(n,msg):
    print("output run")
    for i in range(n):
        print("output forin run")
        print(msg)

if __name__ == '__main__':
    n,msg = getInputData()
    outputData(n, msg)

运行结果:

input run
请输入一个数字:1
请输入一个数据:1
output run
Traceback (most recent call last):
  File "/Users/liusuhui/Desktop/RecordCode/main.py", line 15, in <module>
    outputData(n, msg)
  File "/Users/liusuhui/Desktop/RecordCode/main.py", line 9, in outputData
    for i in range(n):
TypeError: 'str' object cannot be interpreted as an integer

Process finished with exit code 1

在示例代码中,加入了三条 print() 语句,用来输出一些信息,通过运行结果可以看出,input runoutput run 都被正常输出,而 output forin run 没有输出,说明程序在输出该语句之前出现错误,此时就可以通过检查语法信息,上下文逻辑等来判断具体错误原因。

print() 语句在调试代码时,两条语句之间包含多少代码,视具体情况而定。不是必须在每条语句前后都加 print() 输出,在错误调试完成后,需要把输出注释或删除掉。

什么是异常

错误 与 异常的区别?

  • 错误与异常都是在程序编译和运⾏时出现的错误
  • 异常可以被开发⼈员捕捉和处理
  • 错误⼀般是系统错误,⼀般不需要开发⼈员处理(也⽆法处理),⽐如内存溢出

什么是异常?

  • 异常即是⼀个事件,该事件会在程序执⾏过程中发⽣,影响了程序的正常执⾏。
  • 有些是由于拼写、配置、选项等等各种引起的程序错误,有些是由于程序功能处理逻辑不完善引起的漏洞,这些统称为程序中的异常

常见的异常类型

  • 除零异常、名称异常、索引异常、键异常、值异常、属性异常等等

##语法错误与定位
异常处理流程:

  • 检测到错误->引发异常->捕获异常操作

异常解决⽅案

  • 如果是拼写、配置等引起的错误,根据出错信息进⾏排查错误出现的位置进⾏解决
  • 如果是程序设计不完善引起的漏洞,根据漏洞的情况进⾏设计处理漏洞的逻辑

##异常捕获、异常处理



# 相除
# def div(a, b):
#     if b != 0:
#         return a / b
#     else:
#         print('分母不能为0')
#         return 0
def div(a, b):
    return a / b

f = open('data.txt')
try:
    print(div(1, 1))
    list1 = [1, 2, 3]
    print(list1[3])

    f.readlines()
except Exception as e:
    print(e)
    print('这里有个异常')

finally: # finally最终都会被执行,无论有异常还是没有异常的情况
    print('finally')
    f.close()

def set_age(num):
    if num <= 0 or num > 200:
        raise ValueError(f'值错误:{num}')
    else:
        print(f'设置的年龄为:{num}')
        
set_age(-1)

⾃定义异常

语法

raise [Exception [, args [, traceback]]]
class MyError(Exception):
 def __init__(self, value):
 self.value = value
 def __str__(self):
 return repr(self.value)
class MyException(Exception):
    def __init__(self, msg):
        print(f'这是一个异常:{msg}')


def set_age(num):
    if num <= 0 or num > 200:
        raise MyException(f'值错误:{num}')
    else:
        print(f'设置的年龄为:{num}')

set_age(-10)

debug调试与分析

##调试的概念与技术体系

  • 程序调试是将编制的程序投⼊实际运⾏前,⽤⼿⼯或编译程序等⽅法进⾏测
    试,修正【语法错误和逻辑错误】的过程。
  • 语法错误:编写的python语法不正确,程序编译失败。
  • 逻辑错误:代码本⾝能够正常执⾏,但是执⾏完成的结果不符合预期结果。
  • 什么是bug:bug是计算机领域专业术语(⼩昆⾍; ⾍⼦),计算机⾥叫漏洞,隐藏在程序中的⼀些未被发现的缺陷或问题统称为bug(漏洞)

程序调试

  • 1、语法错误
    • 类型错误,语法错误,缩进错误,索引错误,键错误
  • 2、逻辑错误
    • 业务逻辑错误,并不会报错

调试方法

  • 1、对应位置使⽤print 或者 logging打印⽇志信息
  • 2、启动断点模式debug调试

debug调试

还可以通过 PyCharm 的 debug 功能来调试程序,通过 debug功能,还可以监控程序的执行过程。

在使用debug功能时,需要配合程序断点来进行调试。

程序断点

使用 PyCharm 编写代码时,可以在行号后通过点击添加删除断点。

断点的作用是在debug调试程序时,遇到断点程序就会暂停执行,通过点击控制按钮,控制程序向下执行。

调试控制

程序打好断点后,点击debug即可进入debug模式,程序遇到断点就会暂停执行,此时就需要通过控制按钮来控制程序的执行

横向按钮

  • Step Over: 步过按钮,将函数做为一条语句执行,不进入函数内部执行。
  • Step Into: 单步执行,会进入到函数内部逐条执行代码。
  • Step Into My Code: 单步执行,只进入自定义函数内部,不会进入系统函数内部。
  • Step Out: 步出按钮,跳出当前函数体,返回到此函数调用位置
  • Run to Cursor: 运行到光标处,当调试程序时,如果某一行没有打断点,又想暂停,可以将光标移动到目标行,点击该按钮
  • Evaluate Expression: 评估表达式,高级用法,可以在调试过程中查看程序的中间过程,比如查看参数 n 的类型。

竖向按钮

  • Rerun main: 重新运行 debug 功能
  • Modify Run Configuration: 修改运行配置
  • Resume Program: 继续执行,运行到下一断点处,如果没有,程序运行结束
  • Stop main: 停止 Debug
  • View Breakpoints: 显示程序中所有的断点。
  • Mute Breakpoints: 让所有断点失效,使用后所有断点为灰色,debug时,代码不会在断点处暂停。
  • Pin Tab: 钉住当前调试窗口标签,防止关闭。

异常处理

编写程序时,即使语句或表达式使用了正确的语法,执行时仍可能触发错误。执行时检测到的错误称为异常,大多数异常不会被程序处理,程序会中断运行,并抛出异常信息。

如果不想发生异常时,程序被中断执行,可以编写程序处理选定的异常。

try-except

Python 使用 try/except语句捕捉异常。

try/except 语句用来检测 try 语句块中的错误,从而让 except 语句捕获异常信息并处理。

如果你不想在异常发生时结束你的程序,只需在try里捕获它。

n1 = int(input("请输入第一个数:"))
n2 = int(input("请输入第二个数:"))
result = 0
try:
    result = n1 / n2
except Exception:
    print("除数不能为0")

print(result)

image

file = open("data.txt","r")
try:
    # 写入数据时可能会有问题
    file.write("写入的数据")
except IOError as err:
    print("文件不能写入", err)

file.close()

image

捕捉多个异常

如果一段代码可能会发生多种异常,并想在程序中都想处理,可以使用多个 except 分别捕捉异常。

可以捕捉 Exception异常类型来处理所有的异常,如果有多个时,必须放在最后捕捉该异常,否则无法处理到其它异常。

file = open("data.txt","r")
try:
    # 写入数据时可能会有问题
    # file.write("写入的数据")
    # print(a)
    # print(3 / 0)
    # print([][10])
    print("hello" + 100)
except IOError as err:
    print("文件不能写入", err)
except NameError:
    print("标识符没有定义")
except ZeroDivisionError:
    print("除数不能为0")
except IndexError:
    print("下标越界了")
except Exception:
    print("程序运行出错,请检查代码")
file.close()

image

else 操作

Python 使用 else 在处理在代码无异常时的后续操作。

try:
    n = input("请输入一个数字:")
    num = int(n)
except Exception:
    print("元素无法转换为数字")
else:
    print("转换后成功",num)

finally 操作

Python 使用 finally 处理无论异常是否发异,都要执行的代码,一般用来完成清理工作。

try:
   file = open("data.txt","r")
   # file.write("A")
except Exception:
    print("文件操作报错")
finally:
    print("文件已关闭")
    file.close()