Python学习之路9-文件和异常

匿名 (未验证) 提交于 2019-12-02 22:54:36

《Python编程:从入门到实践》笔记。
本章主要是学习Python的文件操作,主要是从文件中读取数据以及将数据存储到文件中,还有错误处理,异常类,json模块等。

以下文件pi_digits.txt包含了精确到小数点后30位的圆周率数据

# pi_digits.txt文件 3.1415926535   8979323846   2643383279  # 代码: with open("pi_digits.txt", "r") as file_object:     contents = file_object.read()   # 一次性读取整个文件     print(contents)  # 结果:和上述文件内容一样

从上述代码可以看出,我们打开文件使用open()函数,该函数至少接收一个参数,即文件路径。读取文件时需要向open()函数指明是用什么方式读取文件,是只读("r"),只写("w"),末尾添加("a")还是读写均可("r+"),open()函数默认以“只读”方式读取文件。这只是4中常用的文件读取方式,此外还有至少8种读写方式。open()函数返回一个文件对象,file_object用于接收该对象。通过文件对象的read()方法读取文件内容,且该方法返回整个文件的内容。

上述代码中的文件和源代码在同一目录中。注意文件路径的问题,绝对路径(不提倡)和相对路径(相对于源文件的路径)以及Windows和Linux下路径的写法。

注意代码中的with关键字。其实读写文件不需要该关键字,打开文件使用open()函数,文件读取完后关闭文件使用close()函数,读取内容可以调用read()方法。而之所以使用with关键字,主要是因为①你最后忘记关闭文件,就想忘了关灯一样;②也可能是在关闭前程序出错,导致close()语句未执行。这些让文件没有关闭的情况都有可能导致数据丢失或损坏。with关键字则被用来应对这些情况,它保证在结束with块时,文件一定会被关闭。

上述代码一次性读取整个文件,这在文件较小或者内存充裕的时候没有问题,但如果文件特别大,内存容量又很羞涩,则只能逐行读取:

# 代码: file_name = "pi_digits.txt"  with open(file_name) as file_pi:     for line in file_pi:  # 也可以通过while循环配合readline()方法逐行读取文件         print(line)  # 结果: 3.1415926535    8979323846    2643383279

这里需要注意一个问题,就是对行以及文件末尾空字符的读取问题,read()readline()方法会读取末尾的空字符(这里是换行符)。我们可以通过之前讲的rstrip()方法去掉末尾的空字符。

readlines()方法将文件中每一行存入列表并返回,以下代码进一步处理文件中的内容:

# 代码: file_name = "pi_digits.txt"  with open(file_name) as file_pi:     lines = file_pi.readlines()  pi_string = "" for line in lines:     pi_string += line.strip()  print(pi_string) print(len(pi_string))  # 结果: 3.141592653589793238462643383279 32

注意,Python从文件中读取出的所有内容都是字符串,如果你想要的是数字,请记得转换。

以下是一个简单的文件写入程序:

filename = "python.txt" with open(filename, "w") as file_obj:     file_obj.write("I love python!")

执行改代码后你会看到在同一目录下会生成一个名为“python.txt”的文件。需要注意的是,以"w"方式打开文件,如果要写入的文件不存在,则会自动创建该文件;如果该文件存在,该文件的内容会被清空,然后再写入。如果不想文件被清空,请使用"a"(文件指针放在文件末尾)或"r+"(文件指针指向文件开头)方式打开文件。还有一点,write()函数不会在文件末尾添加换行符,如果需要换行符,请自行添加。

Python中使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当代码运行时如果遇到了不能处理的错误,Python都会创建一个异常对象,如果程序中没有处理该对象的相关代码,程序将会停止,并显示一个traceback,其中包含异常的相关报告。如果不想程序因为某些异常而终止运行,则需要我们使用try-except代码块自行处理异常。以下是一个处理除零错误ZeroDivisionError的例子:

# 代码: # 捕捉异常 try:     resule = 5 / 0 except ZeroDivisionError:     print("You can't divide by zero!\n")  # 不捕捉异常 print(5 / 0)  # 结果: You can't divide by zero!  Traceback (most recent call last):   File "division.py", line 29, in <module>     print(5 / 0) ZeroDivisionError: division by zero

如果你打算编写一个计算器应用,那么这段代码必不可少。第一个例子表明,即使发生了异常,只要异常被我们捕捉,那么程序便不会终止。如果只想捕捉异常,但暂时又不想处理,可以将上述的print("You can't divide by zero!\n")替换为pass语句。如果想捕获所有的异常,则except后面不指定异常类型。

try-except代码块还可以和else语句组合形成try-except-else代码块,该结构表示,如果捕获了异常,这执行except中的程序,没有发生异常则执行else中的程序。以下程序是一个循环统计文件中单词数的例子,文件读取的部分被放到了函数中,该函数检测有没有发生FileNotFoundError

# 代码: def count_words(filename):     """计算一个文件大致包含多少个单词"""     try:         with open(filename) as f_obj:             contents = f_obj.read()     except FileNotFoundError:         msg = "Sorry, the file" + filename + " does not exist."         print(msg)     else:         # 计算文件大只包含多少个单词         words = contents.split()         num_words = len(words)         print("The file " + filename + " has about " + str(num_words) + "words.")  filenames = ["alice.txt", "siddhartha.txt", "moby_dick.txt", "little_women.txt"] for filename in filenames:     count_words(filename)  # 结果: The file alice.txt has about 29461 words. Sorry, the file siddhartha.txt does not exist. The file moby_dick.txt has about 215136 words. The file little_women.txt has about 189097 words.

else的补充:其实else不光可以和iftry-except结合,还可以和for循环和while循环结合,比如:

for i in range(10):     pass else:     pass  i = 0 while i < 10:     i++ else:     pass

这里的else表示当循环结束后执行一些语句,比如提示之类的。

编写得很好且经过详尽测试的代码不容易出现内部错误,如语法或逻辑错误,但只要程序依赖于外部因素,如用户输入、存在指定的文件、有网络连接等,就有可能出现异常。凭经验可判断改在程序的什么地方包含异常处理块,以及出现错误时该向用户提供多少相关的信息。

很多程序要求用户输入某种信息,也有可能程序中某些变量的数据在程序结束后不能丢失(比如机器学习最后训练出来的模型参数),这是就需要将这些信息以文件的形式存下来。存储数据的方式有很多,现在比较简单且通用的是使用json来存储信息。json(JavaScript Object Notation)格式最初是为JavaScript 开发的,但随后成了一种常见格式,并被包括Python在内的众多语言采用。以下是一个经过了重构的存储用户信息的例子:

import json  def get_stored_username(filename):     """如果存储了用户名,就获取它"""     try:         with open(filename) as f_obj:             username = json.load(f_obj)     except FileNotFoundError:         return None     else:         return username  def get_new_username(filename):     """提示用户输入用户名,并存入文件"""     username = input("What's your name?")     with open(filename, "w") as f_obj:         json.dump(username, f_obj)     return username  def greet_user(filename):     """向用户打招呼"""     username = get_stored_username(filename)     if username:         print("Welcome back, " + username + "!")     else:         username = get_new_username(filename)         print("We'll remember you when you come back, " + username + "!")  filename = "username.json" greet_user(filename)

代码就不运行了,请各位自行推导程序的结果。最后在username.json文件中会存有用户的信息。但要注意一点,json根据数据类型来存储数据,虽然最后都是字符串,但这个过程不需要我们干预,比如要存一个列表,并不需要我们先将其转换为字符串,再存入json,读取数据时也不需要我们先读取为字符串,再转换成列表,我们只需直接存取即可,转换工作由json模块自动完成。


迎大家关注我的微信公众号“代码港” 和
个人网站 www.vpointer.net ~

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!