Python-11.1-文件和异常
文件和异常
- 将学习处理文件,让程序能够快速地分析大量的数据
- 将学习错误处理,避免程序在面对意外情形时崩溃
- 将学习异常,它们是Python创建的特殊对象,用于管理程序运行时出现的错误
- 将学习模块json,它让你能够保存用户数据,以免在程序停止运行后丢失
- 提高程序的适用性、可用性和稳定性
- 学习处理文件和保存数据可让你的程序使用起来更容易:
- 用户将能够选择输入什么样的数据,以及在什么时候输入
- 用户使用你的程序做一些工作后,可将程序关闭,以后再接着往下做
- 学习处理异常:
- 应对文件不存在的情形,以及处理其他可能导致程序崩溃的问题
- 能让程序再面对错误的数据时更健壮
一:从文件中读取数据
- 文本文件可存储的数据量多得难以置信:天气数据、交通数据、社会经济数据等
- 每当需要分析或修改存储在文件中的信息时,读取文件都很用,对数据分析应用程序来说尤其重要
- 可以编写这样的程序
- 读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器能够显示这些内容
- 要使用文本文件的信息,首先需要将信息读取到内存中
1、读取整个文件
- 在G盘文件夹qwh下创建一个名为qaz.txt的文档文件
- 关键字with在不再需要访问文件后将其关闭
- 函数open()接受一个参数:要打开的文件名称
- 函数read()读取这个文件的全部内容
# 函数open()返回一个表示文件的对象
with open(r'G:\qwh\qaz.txt') as file_object:
contents = file_object.read()
print(contents.strip())
3.1415926353
8979323846
2643383279
3、逐行读取
- 读取文件时,常常需要检查其中的每一行
- 在文件中查找特定的信息
- 以某种方式修改文件中的文本
- 要以每次一行的方式检查文件,可对文件对象使用for循环
filename = 'G:\qwh\qaz.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
# 出现空白的原因是
# 在文件中每行的末尾都有一个转行符
# 可在print与剧中使用rstrip()
3.1415926353
8979323846
2643383279
4、创建一个包含文件各行内容的列表
- 使用关键字with时,open()返回的文件对象只在with代码块内使用
- 如果要在代码块外使用该列表:
- 可在with代码块内将文件的各行存储在一个列表中
- 并在with代码块外使用该列表
filename = 'G:\qwh\qaz.txt'
with open(filename) as file_object:
lines = file_object.readlines()
for line in lines:
print(line.rstrip())
3.1415926353
8979323846
2643383279
5、使用文件的内容
- 将文件读取到内存后,就可以以任何方式使用这些数据了
- 使用圆周率的值
- 创建一个字符串,它包含文件中存储的所有数字,且没有任何空格
- 注意:
- 读取文本文件时,Python将其中的所有文本都解读为字符串
- 如果读取的是数字,并要将其作为数值使用,就必须使用函数int()
- 或使用函数float()将其转换为浮点数
filename = 'G:\qwh\qaz.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string)
3.141592635389793238462643383279
a = '8.5'
a = float(a)
a = int(a)
if a > 0:
print(a)
8
6、包含一百万位的大型文件
- 如果有一个文本文件,其中包含精确到小数点后1000000位而不是30位的圆周率,也可以创建一个包含所有这些数字的字符串
- 只需将这个文件传递给它即可
filename = 'G:\qwh\qaz_million.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string[:10])
print(len(pi_string))
3.14159263
9912
7、圆周率中包含你的生日吗
filename = 'G:\qwh\qaz_million.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
birthday = input("Enter your birthday:")
if birthday in pi_string:
print("Your birthday appears in the first million digits of pi!")
else:
print("Your birthday does not appear in the first million digits of pi.")
Enter your birthday:961006
Your birthday does not appear in the first million digits of pi.
二:写入文件
- 保存数据的最简单的方式之一是将其写入到文件中
- 通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在
- 可以在程序结束运行后查看这些输出
- 可与别人分享输出文件
- 可编写程序来将这些输出读取到内存中并进行处理
1、写入空文件
- 要将文本写入文件,在调用open()时需提供另一个实参,告诉Python要写入打开的文件
- 调用open()提供两个参数
- 第一个实参是要打开的文件名称
- 第二个实参(‘w’)告诉Python以写入模式打开这个文件
- 打开文件时,可指定
- 读取模式(‘r’)
- 写入模式(‘w’)
- 附加模式(‘a’)
- 读取和写入文件模式(‘r+’)
- 如果省略了模式实参,Python将以默认的只读模式打开文件
- 注意:
- 如果写入的文件不存在,函数open()将自动创建
- 以写入(‘r’)模式打开文件时,如果指定的文件已经存在,Python将在返回文件对象前清空该文件
- Python只能将字符串写入文本文件
- 要将数值数据存入到文本文件中,必须先使用函数str()将其转换为字符串格式
# 写入文件案例
file_name = 'G:\qwh\programming.txt'
with open(file_name, 'w') as file_object:
file_object.write("I am superman.")
# 将数值数据转换成字符串写入文本文件
file_name = 'G:\qwh\int.txt'
a = 123
with open(file_name, 'w') as file_object:
file_object.write(str(a))
2、写入多行
- 函数write()不会在你写入的文本末尾添加换行符
# version1.0
file_name = 'G:\qwh\programming.txt'
with open(file_name, 'w') as file_object:
file_object.write('I like apple.')
file_object.write('I like banana.')
file_object.write('I like pear.')
# version2.0
file_name = 'G:\qwh\programming.txt'
apple = 'I like apple.\n'
banana = 'I like banana.\n'
pear = 'I like pear.\n'
with open(file_name, 'w') as file_object:
file_object.write(apple + banana + pear)
3、附加到文件
- 要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件
- 以附加模式打开文件时,Python不会返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾哦
- 如果指定的文件不存在,Python将为你创建一个空文件
file_name = 'G:\qwh\programming.txt'
fruits = "I like this fruit very much."
with open(file_name, 'a') as file_object:
file_object.write(fruits)
三:异常
- Python使用被称为异常的特殊对象来管理程序执行期间发生的错误
- 每当发生让Python不知所措的错误时,它都会创建一个异常对象
- 如果你编写了处理该异常的代码,程序将继续运行
- 如果你未对异常进行处理。程序将停止,并显示一个traceback,其中包含有关异常的报告
- 异常是使用try-except代码块处理的
- try_except代码块让Python执行指定的操作,同时告诉Python发生异常时该怎么办
- 使用了try-except代码块时,即便出现异常,程序也将继续运行
- 显示你编写的友好的错误信息,而不是令用户迷惑的traceback
1、处理ZeroDivisionError异常
- Python无法按要求做时,就会创建一个ZeroDivisionError异常对象
- Python将停止运行程序,并指出引发了哪种异常,而我们可根据这些信息对程序进行修改
- 如果再次发什么这样的错误,就有备无患了
2、使用try-except代码块
- 可编写一个try-except代码块来处理可能引发的异常
- 让Python尝试运行一些代码,并告诉它如果这些代码引发了指定的异常,该怎么办
- 如果try-except代码块后面还有其他代码,程序将接着运行
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
print(5/2)
You can’t divide by zero!
2.5
3、使用异常避免崩溃
- 发生错误时,如果程序还有工作没有完成,妥善地处理错误尤其重要
# 只执行除法运算的简单计算器
# 此程序未采取任何处理错误的措施
print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit")
while True:
first_number = input("\nFirst number:")
if first_number == 'q':
break
second_number = input("Second number:")
if second_number == 'q':
break
answer = int(first_number) / int(second_number)
print(answer)
4、else代码块
- 通过将可能引发错误的代码放在try-except代码块中,可提高这个程序抵御错误的能力
- 将可能引发错误的代码放在try代码块中
- 依赖于try代码块成功执行的代码都放在self代码块中
- except代码块当try代码块中的代码发生指定异常时将告诉Python如何处理
# 采取处理错误的措施
print("Give me two numbers, and I'll divide them.")
print("Enter 'q' to quit")
while True:
first_number = input("\nFirst number:")
if first_number == 'q':
break
second_number = input("Second number:")
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("You can't divide by 0.")
else:
print(int(answer))
Give me two numbers, and I’ll divide them.
Enter ‘q’ to quit
First number:6
Second number:3
2
First number:6
Second number:0
You can’t divide by 0.
First number:q
5、处理FileNotFound异常
- 使用文件时,一种常见的问题是找不到文件
- 查找的文件在其他地方
- 文件名可能不正确或者文件根本不存在
- 可以使用try-except代码块以直观的方式进行处理
# FileNotFound异常
file_name = r'G:\qwh\dsa.txt'
try:
with open(file_name) as file_object:
contents = file_object.read()
except FileNotFoundError:
msg = "Sorry, the file " + file_name + " does not exist."
print(msg)
else:
print(contents)
Sorry, the file G:\qwh\dsa.txt does not exist.
6、分析文本
- 分析文本文件,尝试计算它包含多少个单词
- 使用方法split()
- 以空格分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中
- 结果是一个包含字符串中所有单词的列表。虽然有些单词可能包含标点
file_name = r'G:\qwh\programming.txt'
try:
with open(file_name) as file_object:
contents = file_object.read()
except FileNotFoundError:
msg = "Sorry, the file " + file_name + " does not exist."
print(msg)
else:
words = contents.split()
num_words = str(len(words))
print("The file " + file_name + " has about " + num_words + " words.")
The file G:\qwh\programming.txt has about 120 words.
7、使用多个文件
- 分析多个文件时,可将这个程序的大部分代码移到一个名为count_words()函数中
- try-except代码块提供了两个重要的优点
- 避免用户看到tracebook
- 让程序能够继续分析能找到的其他文件
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as file_object:
contents = file_object.read()
except FileNotFoundError:
msg = "Sorry, the file " + file_name + " does not exist."
print(msg)
else:
words = contents.split()
num_words = str(len(words))
print("The file " + file_name + " has about " + num_words + " words.")
filenames = [r"G:\qwh\programming.txt", r"G:\qwh\tgb.txt", r"G:\qwh\favorite.txt"]
for filename in filenames:
count_words(filename)
print("\n")
The file G:\qwh\programming.txt has about 120 words.
Sorry, the file G:\qwh\programming.txt does not exist.
The file G:\qwh\programming.txt has about 336 words.
8、失败时一声不吭
- 并非每次捕获到异常都需要告诉用户
- 可使用语句pass,充当占位符,表示什么都不做
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename) as file_object:
contents = file_object.read()
except FileNotFoundError:
pass
else:
words = contents.split()
num_words = str(len(words))
print("The file " + filename + " has about " + num_words + " words.")
filenames = [r"G:\qwh\programming.txt", r"G:\qwh\tgb.txt", r"G:\qwh\favorite.txt"]
for filename in filenames:
count_words(filename)
print("\n")
The file G:\qwh\programming.txt has about 3 words.
The file G:\qwh\favorite.txt has about 336 words.
四:存储数据
- 很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据
- 程序都把用户提供的信息存储在列表和字典等数据结构中
- 一种简单的方式是使用json来存储数据
- 模块json让你能够将简单的Python数据结构存储到文件中,并在程序再次运行时加载该文件中的数据
1、使用 json.dump() 和 json.load()
- 函数 json.dump() :
- 将数据结构存储到文件中
- 接受两个实参:
- 要存储的数据
- 可用于存储数据的文件对象
- 函数 json.load() :
- 将数据读取到内存中
- 接受一个实参:
- 可用于存储数据的文件对象
- 通常使用文件扩展名.json来指出文件存储的数据为JSON格式
# json.dump()
import json
numbers = [1, 5, 9, 8, 4, 2, 6, 7]
filename = r"G:\qwh\number.json"
with open(filename, 'w') as f_obj:
json.dump(numbers, f_obj)
# json.load()
import json
filename = r"G:\qwh\number.json"
with open(filename) as f_obj:
numbers = json.load(f_obj)
print(numbers)
[1, 5, 9, 8, 4, 2, 6, 7]
2、保存和读取用户生成的数据
- 对于生成的数据,使用json保存它们大有裨益
- 程序停止运行时用户的信息将会保存下来而不会丢失
# 1、保存数据
import json
username = input('Whis is your name?')
filename = r'G:\qwh\username.json'
with open(filename, 'w') as f_obj:
# 将用户名和一个文件对象传递给它
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username.title() + ".")
Whis is your name?jack
We’ll remember you when you come back, Jack.
# 2、读取数据
import json
filename = r"G:\qwh\username.json"
with open(filename) as f_obj:
username = json.load(f_obj)
print("Welcome back, " + username + ".")
Welcome back, jack.
# 3、当读取的数据不存在时
import json
# 如果以前存储了用户名,就加载它
# 否则,就提示用户输入用户名并存储它
filename = r"G:\qwh\username.json"
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("Whis is your name?")
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username.title() + ".")
else:
print("Welcome back, " + username.title() + ".")
Welcome back, Jack.
3、重构
- 将代码划分为一系列完成具体工作的函数,这样的过程被称为重构
- 重构让代码更清晰、更易于理解、更容易扩展
- 要重构,可将其大部分逻辑放到一个或多个函数中
# version1.0
import json
def greet_user():
"""问候用户,并指出其名字"""
filename = r"G:\qwh\username.json"
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name?")
with open(filename, 'w') as f_object:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username.title() + ".")
else:
print("Welcome back, " + username.title() + ".")
greet_user()
Welcome back, Jack.
# version2.0
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
filename = r"G:\qwh\username.json"
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def greet_user():
"""问候用户指出名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username.title())
else:
username = input("What is your name?")
filename = r"G:\qwh\username.json"
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username.title() + ".")
greet_user()
Welcome back, Jack
- 最终版本中,每个函数都执行单一而清晰的任务
- 当我们调用greet_user(),它打印一条合适的消息
- 要么欢迎老用户回来
- 要么问候新用户
- 为此,它首先调用get_stored_username(),这个函数只负责获取存储的用户名(如果存储的话)
- 再在必要时调用get_new_username(),这个函数只负责获取并存储新用户的用户名
- 要编写除清晰而易于维护和扩展的代码,这种划分工作必不可少
# version3.0
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
filename = r"G:\qwh\username.json"
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def greet_new_username():
"""提示用户输入名字"""
username = input("What is your name?")
filename = r"G:\qwh\username.json"
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
return username
def greet_user():
"""问候用户,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username.title() + ".")
else:
username = greet_new_username()
print("We'll remember you when you come back, " + username.title() + ".")
greet_user()
Welcome back, Jack
五:小结
- 如何使用文件
- 如何一次性读取整个文件,以及如何以每次一行的方式读取文件的内容
- 如何写入文件,以及如何将文本附加到文件末尾
- 什么是异常以及如何处理程序可能引发的异常
- 如何存储Python数据结构,以保存用户提供的信息,避免用户每次运行程序都需要重新提供