资讯专栏INFORMATION COLUMN

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

chenatu / 2162人阅读

摘要:本章主要是学习的文件操作,主要是从文件中读取数据以及将数据存储到文件中,还有错误处理,异常类,模块等。函数返回一个文件对象,用于接收该对象。异常中使用被称为异常的特殊对象来管理程序执行期间发生的错误。

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

以下文件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块时,文件一定会被关闭。

1.2 逐行读取

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

# 代码:
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()方法去掉末尾的空字符。

1.3 将文件每一行放入列表中

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从文件中读取出的所有内容都是字符串,如果你想要的是数字,请记得转换。

2. 写入文件

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

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

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

3. 异常

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

# 代码:
# 捕捉异常
try:
    resule = 5 / 0
except ZeroDivisionError:
    print("You can"t divide by zero!
")

# 不捕捉异常
print(5 / 0)

# 结果:
You can"t divide by zero!

Traceback (most recent call last):
  File "division.py", line 29, in 
    print(5 / 0)
ZeroDivisionError: division by zero

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

3.1 else代码块

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表示当循环结束后执行一些语句,比如提示之类的。

3.2 决定报告哪些错误

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

4. 存储数据

很多程序要求用户输入某种信息,也有可能程序中某些变量的数据在程序结束后不能丢失(比如机器学习最后训练出来的模型参数),这是就需要将这些信息以文件的形式存下来。存储数据的方式有很多,现在比较简单且通用的是使用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 ~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41792.html

相关文章

  • Python学习之路21-序列构成的数组

    摘要:第行把具名元组以的形式返回。对序列使用和通常号两侧的序列由相同类型的数据所构成当然不同类型的也可以相加,返回一个新序列。从上面的结果可以看出,它虽抛出了异常,但仍完成了操作查看字节码并不难,而且它对我们了解代码背后的运行机制很有帮助。 《流畅的Python》笔记。接下来的三篇都是关于Python的数据结构,本篇主要是Python中的各序列类型 1. 内置序列类型概览 Python标准库...

    ralap 评论0 收藏0
  • scrapy 学习之路上的那些坑

    摘要:前言本文记录自己在学习当中遇到的各种大小问题,持续更新。错误分析本身是一个网络引擎框架,的运行依赖于。在打开新建的项目后,报错显示。错误分析的默认依赖项当中没有,或者说默认查找的路径中找不到。 前言 本文记录自己在学习scrapy当中遇到的各种大小问题,持续更新。 环境简介: 语言版本 爬虫框架 IDE 系统 python3.5 scrapy1.4.0 pycharm win1...

    xiaodao 评论0 收藏0
  • Python学习之路29-序列的修改、散列切片

    摘要:具体方法和上一篇一样,也是用各个分量的哈希值进行异或运算,由于的分量可能很多,这里我们使用函数来归约异或值。每个分量被映射成了它们的哈希值,这些哈希值再归约成一个值这里的传入了第三个参数,并且建议最好传入第三个参数。 《流畅的Python》笔记。本篇是面向对象惯用方法的第三篇。本篇将以上一篇中的Vector2d为基础,定义多维向量Vector。 1. 前言 自定义Vector类的行为...

    马忠志 评论0 收藏0
  • Python学习之路30-接口:从协议到抽象基类

    摘要:本篇内容将从鸭子类型的动态协议,逐渐过渡到使接口更明确能验证实现是否符合规定的抽象基类。抽象基类介绍完动态实现接口后,现在开始讨论抽象基类,它属于静态显示地实现接口。标准库中的抽象基类从开始,标准库提供了抽象基类。 《流畅的Python》笔记。本篇是面向对象惯用方法的第四篇,主要讨论接口。本篇内容将从鸭子类型的动态协议,逐渐过渡到使接口更明确、能验证实现是否符合规定的抽象基类(Abst...

    LucasTwilight 评论0 收藏0
  • Python学习之路15-下载数据

    摘要:本节中将绘制幅图像收盘折线图,收盘价对数变换,收盘价月日均值,收盘价周日均值,收盘价星期均值。对数变换是常用的处理方法之一。 《Python编程:从入门到实践》笔记。本篇是Python数据处理的第二篇,本篇将使用网上下载的数据,对这些数据进行可视化。 1. 前言 本篇将访问并可视化以两种常见格式存储的数据:CSV和JSON: 使用Python的csv模块来处理以CSV(逗号分隔的值)...

    张春雷 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<