python-文件和异常

简介

本章中你将学习处理文件,让程序能够快速地分析大量数据;你将学习错误处理,避免程序在面对意外情形时崩溃;你将学习异常,他们是Python创建的特殊对象,用于管理程序运行时出现的错误;你还将学习模块json,它让你能够保存用户数据,以免在程序停止运行后丢失。

从文件中读取数据

文本文件可存储的数据量多得难以置信,天气数据,交通数据,社会经济数据等。因此读取文件很重要,对数据分析应用程序来说尤其如此。
示例:编写一个程序,实现读取一个文本文件内容,重新设置这些数据的格式再写入文件中,让浏览器可以显示这些内容。
首先需要将信息读取到内存中,你可以一次性读取文件的全部内容,也可以每次一行的方式逐步读取。

读取整个文件

首先创建一个名为pi_digits.txt的文件,并写入一些文字。
读取文件

with open('pi_digits.txt') as file_object:
    contents=file_object.read()
    print(contents)

提示:

  1. 在程序中我们调用了open()但没有调用close();你也可以调用open()和close()来打开和关闭文件。但这样做可能会产生很多问题:如果程序存在bug,导致close()语句未执行,文件将不会关闭。可能会导致数据丢失;如果过早地调用了close(),在你需要访问时可能会导致无法访问。
    故你可以不适用close()函数去关闭,让Python自己去确定;你只管打开文件,并在需要时使用它,Python自会在合适的时候自动关闭它。
  2. 输出的结果会多一个空行,因为read()后面会返回一个空字符串。可在print中使用rstrip()方法,去掉空行。

文件路径

要让Python打开不与程序文件位于同一个目录下的文件,需要提供文件路径,它让Python到特定的位置去查找。
可以使用相对路径和绝对路径。
相对路径

with open('text_files/filename.txt') as file_object:

注意:在Windows系统中,路径要使用反斜杠 \ ;另外由于反斜杠在Python中被视为转义字符,为确保万无一失,应以原始字符串的方式指定路径,即在开头的单引号前加上r。

绝对路径

file_path='/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:

逐行读取

要以每次一行的方式检查文件,可对文件对象使用for循环。

fielname='pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line)

注意:输出结果为每行后有两个空行,因为在这个文件中,每行的末尾都有一个看不见的换行符,而print语句也会加上一个换行符,因此每行后都有两个换行符:一个来自文件,另一个来自print语句。
要消除这些多余的空白行,可在print语句后使用rstrip().

filename='pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())

创建一个包含文件各行内容的列表

使用关键字with时,open()返回的文件对象只在with代码块内可用,若果要在with代码块外访问文件内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表。

filename='pi_digits.txt'
with open(filename) as file_object:
    lines=file_object.readlines()
for line in lines:
    print(line.rstrip())

使用文件的内容

将文件读取到内存后就可以以任何方式读取这些数据了。
示例:将包含圆周率的文本打开,把其中的数字放入一个字符串中,且没有任何空格。

filename='pi_digits.txt'
with open(filename) as file_object:
    lines=file_object.readlines()
pi_string=''
for line in lines:
    pi_string+=line.strip()
print(pi_string)
print(len(pi_string))

包含一百万位的大型文件

文件中包含一百万位的数字,这里我们只打印到小数点后两位,以免终端为显示全部而不断翻滚。

filename='pi_million_digits.txt'
with open(filename) as file_object:
    lines=file_object.readlines()
pi_string=''
for line in lines:
    pi_string+=line.strip()
print(pi_string[:52])
print(len(pi_string))

圆周率值中包含你的生日吗

扩展刚才编写的程序,以确定某人的生日是否包含在圆周率的前一百万位中。
可将生日表示为一个由数字组成的字符串,再检查这个字符串是否包含在其中。

filename='pi_million_digits.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, in the form mmddyy:")
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.")

写入文件

保存数据最简单的方式之一是将其写入到文件中。通过将输出写入文件,即便关闭包含程序输出的最终端口,这些输出也依旧存在:你可以在程序结束运行后查看这些输出,可以与别人分享输出文件,还可以编写程序来将这些输出读取到内存中并处理。

写入空文件

调用open()时提供两个实参,一个为要打开文件的名称,第二个为告诉Python为写入。
打开文件可指定读取r,写入 ‘w’,附加 ‘a’,或让你能够读取和写入的’ r+’
注意:如果你要写入的文件不存在,函数open()将自动创建它。然而以写入(‘w’)模式打开文件时,如果指定的文件已经存在,Python将在返回文件对象前清空该文件。
Python只能将字符串写入文本文件,要将数值写入文本文件,必须要先使用函数str()将其转换为字符串格式。

filename='programming.txt'
with open(filename,'w') as file_object:
    file_object.write("I love programming.")

写入多行

函数write()不会在你写入文件的末尾添加换行符,因此如果你写入多行时没有指定换行符,文件看起来可能不是你希望的那样。

filename='programming.txt'
with open(filename,'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")

附加到文件

如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。同时,如果文件不存在,Python也将为你创建一个空文件。

filename='programming.txt'
with open(filename,'a') as file_object:
    file_object("I am love finding meaning in large datasets.\n")
    file_object("I love creating apps that can run in a browser.\n")

异常

Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,它都会创建一个异常对象,如果你编写了处理异常的代码,程序将继续运行;否则,程序将停止运行,并显示一个traceback。
异常是使用try–except代码块处理的。

处理ZeroDivisionError异常

你可能知道不能将一个数字除以0,但我们还是让Python这样做吧!

print(5/0)

在这种情况下,Python将停止运行程序,并指出引发了那种异常,而我们可根据这些信息对程序进行修改。下面我们将告诉Python,发生这种错误该怎么办。

使用try–except代码块

try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

使用异常避免崩溃

发生错误时,如果程序还有工作没有完成,妥善地处理错误就尤其重要。这种情况会出现在要求用户提供输入的程序中;如果程序能够妥善地处理无效输入,就能再提示用户输入有效数据,而不会崩溃。

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(answer)

处理FileNotFoundError异常

在使用文件时,一种常见的问题是找不到文件:你要查找的文件可能在其他地方,文件名可能不正确或者这个文件根本就不存在。对于这些情形,都可以使用try–except代码块来处理。

filename='alice.txt'
with open(filename) as f_obj:
    contents=f_obj.read()

更改为:

filename='alice.txt'
try:
    with open(filename) as f_obj:
        contents=f_obj.read()
except FileNotFoundError:
    msg="sorry,the file "+filename+" does not exist."
    print(msg)

分析文本

使用方法split(),方法sploit(),以空格为分隔符将字符串拆分为多个部分,并将这些部分都存储到一个列表中。结果为一个包含字符串所有单词的列表。

title="Alice in wonderland"
a=title.split()
print(a)

故我们用这个方法来计算小说的单词量。
将小说放入文本alice.txt

filename='alice.txt'
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.")

使用多个文件

下面多分析几本书,这样做之前,我们先将这个程序的大部分代码移到一个名为count_words()的函数中,方便调用。

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.")

编写一个简单的循环,来计算分析任何文本包含多少个单词。

def count_words(filename):
    --snip--
filenames=['alice.txt','siddhartha.txt','moby_dick.txt','little_women.txt']
for filename in filenames:
    count_words(filename)

失败时一声不吭

有时候,你需要让程序在发生异常时一声不吭,但在except代码中明确告诉Python什么都不要做。可以使用pass语句。

def count_words(filename):
    try:
        with open(filename) as f_obj:
            contents=f_obj.read()
    except FileNotFoundError:
        pass
    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

动手试一试

提示用户输入数字,如果用户输入的不是数字会报错,尝试让程序不要报错并继续运行。


def number(num):
    try:
        result=int(num)
        print(result)
    except:
        print("\ncan't input another.")
num=input("please input number:")
while num:
    if num != 'q':
        number(num)
        num=input("please input number:")
    else:
        break

存储数据

当用户把信息提供给程序时,程序都把数据存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们的信息;一种简单的方式是使用模块json来存储数据。
模块json让你能够将简单的python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。
你还可以使用json在Python程序中分享数据,更重要的是json并非Python专用,你还可以将以json格式存储的数据与其他编程语言的人分享。
注意:json格式最初是为JavaScript开发的,但随后成了一种常见格式,被包括Python的众多语言采用。

使用json.dump()和json.load()

使用json.dump()来存储数字列表。
json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象。

import json
numbers=[2,3,5,7,11,13]
filename='numbers.json'
with open(filename,'w') as f_obj:
    json.dump(numbers,f_obj)

再编写一个程序,使用json.load()将这个列表读取到内存中。

import json
filename='numbers.json'
with open(filename) as f_obj:
    numbers=json.load(f_obj)
print(number)

保存和读取用户生成的数据

存储用户的名字

import json
username=input("what is your name?")
filename='username.json'
with open(filename,'w') as f_obj:
    json.dump(username,f_obj)
    print("\nWe'll remember you when you come back, "+username+"!")

再编写一个程序,向其名字被存储的用户发出问候。

import json
filename='username.json'
with open(filename) as f_obj:
    username=json.load(f_obj)
    print("welcome back, "+username+'.')

将这两个程序合并到一个程序,当程序运行时,我们将尝试从文件username.json中获取用户名,如果这个文件不存在,我们就在except代码块中提示用户输入用户名,并将其存储在username.json中,以便程序再次运行时能够获取它。

import json
filename='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_obj:
        json.dump(username,f_obj)
        print("we'll remember you when you come back, "+username+"!")
else:print("welcome back, "+username+'!')

重构

当代码能够正确地运行,但可以做进一步的改进–将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。
重构让代码更清晰,更易于理解,更容易扩展。
重构remember_me.py

import json
def get_stored_username():
    filename='username.json'
    try:
        with open(filename) as f_bjc:
            username=json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username
def get_new_username():
    username=input("What is your name?")
    filename='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+"!")
    else:
        username=get_new_username()
        print("We'll remember you when you come back, "+username+'!')
greet_user()

它将原来的程序,分成了三个部分,先调用get_stored_username(),这个函数只负责获取存储的用户名(如果存储了的话),如果没有存储将调用get_new_username(),这个函数只负责获取并存储新用户的用户名。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ee .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值