• python-文件和异常


    简介

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

    从文件中读取数据

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

    读取整个文件

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

    with open('pi_digits.txt') as file_object:
        contents=file_object.read()
        print(contents)
    
    • 1
    • 2
    • 3

    提示:

    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:
    
    • 1

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

    绝对路径

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

    逐行读取

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

    fielname='pi_digits.txt'
    with open(filename) as file_object:
        for line in file_object:
            print(line)
    
    • 1
    • 2
    • 3
    • 4

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

    filename='pi_digits.txt'
    with open(filename) as file_object:
        for line in file_object:
            print(line.rstrip())
    
    • 1
    • 2
    • 3
    • 4

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

    使用关键字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())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用文件的内容

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

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    包含一百万位的大型文件

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

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

    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.")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    写入文件

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

    写入空文件

    调用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.")
    
    • 1
    • 2
    • 3

    写入多行

    函数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")
    
    • 1
    • 2
    • 3
    • 4

    附加到文件

    如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。同时,如果文件不存在,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")
    
    • 1
    • 2
    • 3
    • 4

    异常

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

    处理ZeroDivisionError异常

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

    print(5/0)
    
    • 1

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

    使用try–except代码块

    try:
        print(5/0)
    except ZeroDivisionError:
        print("You can't divide by zero!")
    
    • 1
    • 2
    • 3
    • 4

    使用异常避免崩溃

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

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    处理FileNotFoundError异常

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

    filename='alice.txt'
    with open(filename) as f_obj:
        contents=f_obj.read()
    
    • 1
    • 2
    • 3

    更改为:

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    分析文本

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

    title="Alice in wonderland"
    a=title.split()
    print(a)
    
    • 1
    • 2
    • 3

    故我们用这个方法来计算小说的单词量。
    将小说放入文本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.")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    使用多个文件

    下面多分析几本书,这样做之前,我们先将这个程序的大部分代码移到一个名为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.")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

    def count_words(filename):
        --snip--
    filenames=['alice.txt','siddhartha.txt','moby_dick.txt','little_women.txt']
    for filename in filenames:
        count_words(filename)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    失败时一声不吭

    有时候,你需要让程序在发生异常时一声不吭,但在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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    动手试一试

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

    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    存储数据

    当用户把信息提供给程序时,程序都把数据存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们的信息;一种简单的方式是使用模块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)
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    import json
    filename='numbers.json'
    with open(filename) as f_obj:
        numbers=json.load(f_obj)
    print(number)
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    存储用户的名字

    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+"!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    import json
    filename='username.json'
    with open(filename) as f_obj:
        username=json.load(f_obj)
        print("welcome back, "+username+'.')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    将这两个程序合并到一个程序,当程序运行时,我们将尝试从文件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+'!')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    重构

    当代码能够正确地运行,但可以做进一步的改进–将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。
    重构让代码更清晰,更易于理解,更容易扩展。
    重构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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

  • 相关阅读:
    JAVA1.8 jdk安装教程
    了解计算机里非门组成的部分
    ssm基于微信小程序的医学健康管理系统
    基于CppHttpLib的Httpserver
    Oracle数据库:oracle外连接left/right/full outer join on,oracle扩展的左右外连接展示符号(+)
    Go 语言接口及使用接口实现链表插入
    Kubernetes带你从头到尾捋一遍
    GTK进行rgb绘图
    Redis —— 自动主从切换
    【Vuex】状态管理机制
  • 原文地址:https://blog.csdn.net/m0_61786761/article/details/126796219