Python基础知识(四)
Python基础知识(四)
一、文件和异常
1、从文件中读取数据
pi_digits.txt
1 | 3.1415926535 |
1 | with open('pi_digits.txt') as file_object: |
在这个程序中,第一行代码做了大量的工作。我们先来看看函数open() 。要以任何方式使用文件,那怕仅仅是打印其内容,都得先打开 文件,才能访问它。函数open() 接受一个参数:要打开的文件的名称。Python在当前执行的文件所在的目录中查找指定的文件。在本例中,当前运行的是file_reader.py,因此Python在file_reader.py所在的目录中查找pi_digits.txt。函数open() 返回一个表示文件的对象。在这里,open(‘pi_digits.txt’) 返回一个表示文件pi_digits.txt的对象,Python将该对象赋给file_object供以后使用。
关键字with在不再需要访问文件后将其关闭。在这个程序中,注意到我们调用了 open() ,但没有调用close() 。也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug导致方法close()未执行,文件将不会关闭。这看似微不足道,但未妥善关闭文件可能导致数据丢失或受损。如果在程序中过早调用close() ,你会发现需要使用文件时它已关闭(无法访问),这会导致更多的错误。并非在任何情况下都能轻松确定关闭文件的恰当时机,但通过使用前面所示的结构,可让Python去确定:你只管打开文件,并在需要时使用它,Python 自会在合适的时候自动将其关闭。
有了表示pi_digits.txt的文件对象后,使用方法read()(前述程序的第二行)读取这个文件的全部内容,并将其作为一个长长的字符串赋给变量contents 。这样,通过打印contents的值,就可将这个文本文件的全部内容显示出来:
1 | 3.1415926535 |
相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。为何会多出这个空行呢?因为read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在函数调用print()中使用 rstrip()。
文件路径
相对文件路径
1 | with open('text_files/filename.txt') as file_object: |
注意 显示文件路径时,Windows系统使用反斜杠(\ )而不是斜杠(/ ), 但在代码中依然可以使用斜杠。
绝对文件路径
1 | file_path = '/home/ehmatthes/other_files/text_files/_filename_.txt' |
绝对路径通常比相对路径长,因此将其赋给一个变量,再将该变量传递给open()会有所帮助。
通过使用绝对路径,可读取系统中任何地方的文件。就目前而言,最简单的做法是,要么将数据文件存储在程序文件所在的目录,要么将其存储在程序文件所在目录下的一个文件夹(如text_files)中。
注意 如果在文件路径中直接使用反斜杠,将引发错误,因为反斜杠用于对字符串中的字符进行转义。例如,对于路径”C:\path\to\file.txt” ,其中的\t将被解读为制表符。如果一定要使用反斜杠,可对路径中的每个反斜杠都进行转义,如”C:\\path\\to\\file.txt” 。
逐行读取
1 | ❶ filename = 'pi_digits.txt' |
在❶处,将要读取的文件的名称赋给变量filename 。这是使用文件时的一种常见做法。变量filename表示的并非实际文件——它只是一个让Python知道到哪里去查找文件的字符串,因此可以轻松地将’pi_digits.txt’ 替换为要使用的另一个文件的名称。调用open()后,将一个表示文件及其内容的对象赋给了变量 file_object(见❷)。这里也使用了关键字with ,让Python负责妥善地打开和关闭文件。为查看文件的内容,通过对文件对象执行循环来遍历文件中的每一行(见❸)。
打印每一行时,发现空白行更多了
1 | 3.1415926535 |
为何会出现这些空白行呢?因为在这个文件中,每行的末尾都有一个看不见的换行符,而函数调用print()也会加上一个换行符,因此每行末尾都有两个换行符:一 个来自文件,另一个来自函数调用print() 。要消除这些多余的空白行,可在函数调用print()中使用rstrip()。
创建一个包含文件各行内容的列表
使用关键字with时,open()返回的文件对象只在with代码块内可用。如果要在with代码块外访问文件的内容,可在with 代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表:可以立即处理文件的各个部分,也可以推迟到程序后面再处理。
1 | filename = 'pi_digits.txt' |
❶处的方法readlines()从文件中读取每一行,并将其存储在一个列表中。接下来,该列表被赋给变量lines 。在with代码块外,依然可使用这个变量。在❷ 处,使用一个简单的for循环来打印lines中的各行。因为列表lines的每个元素都对应于文件中的一行,所以输出与文件内容完全一致。
注意 读取文本文件时,Python将其中的所有文本都解读为字符串。如果读取的是数,并要将其作为数值使用,就必须使用函数int()将其转换为整数或使用函数float()将其转换为浮点数。
2、写入文件
写入空文件
1 | filename = 'programming.txt' |
在本例中,调用open()时提供了两个实参(见❶)。第一个实参也是要打开的文件的名称。第二个实参(’w’ )告诉Python,要以 写入模式打开这个文件。打开文件时,可指定读取模式 (’r’ )、 写入模式 (’w’ )、 附加模式 (’a’ )或读写模式(’r+’ )。如果省略了模式实参,Python将以默认的只读模式打开文件。
如果要写入的文件不存在,函数open()将自动创建它。然而,以写入模式(’w’ )打开文件时千万要小心,因为如果指定的文件已经存在,Python将在返回文件对象前清空该文件的内容。
在❷处,使用文件对象的方法write() 将一个字符串写入文件。这个程序没有终端 输出,但如果打开文件programming.txt,将看到其中包含如下一行内容:
programming.txt
1 | I love programming. |
注意 Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
写入多行
函数write()不会在写入的文本末尾添加换行符,因此如果写入多行时没有指定换行符,文件看起来可能不是你希望的那样
要让每个字符串都单独占一行,需要在方法调用write()中包含换行符
附加到文件
如果要给文件添加内容,而不是覆盖原有的内容,可以以附加模式 打开文件。以附加模式打开文件时,Python不会在返回文件对象前清空文件的内容,而是将写入文件的行添加到文件末尾。如果指定的文件不存在,Python将为你创建一个空文件。
3、异常
Python使用称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,它都会创建一个异常对象。如果你编写了处理该异常的 代码,程序将继续运行;如果未对异常进行处理,程序将停止并显示traceback,其 中包含有关异常的报告。
异常是使用try-except代码块处理的。try-except代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。使用try-except 代码块时,即便出现异常,程序也将继续运行:显示你编写的友好的错误消息,而不是令用户迷惑的traceback。
使用 try-except 代码块处理异常
1 | try: |
将导致错误的代码行print(5/0) 放在一个try代码块中。如果try代码块中的 代码运行起来没有问题,Python将跳过except代码块;如果try 代码块中的代码导致了错误,Python将查找与之匹配的except代码块并运行其中的代码。
else代码块
1 | --snip-- |
让Python尝试执行try代码块中的除法运算(见❶),这个代码块只包含可能导致错误的代码。依赖try代码块成功执行的代码都放在else 代码块中。在本例中, 如果除法运算成功,就使用else 代码块来打印结果(见❸)。
except代码块告诉Python,出现ZeroDivisionError异常时该如何办(见 ❷)。如果try代码块因除零错误而失败,就打印一条友好的消息,告诉用户如何避免这种错误。
try-except-else 代码块的工作原理大致如下。Python尝试执行try代码块中的 代码,只有可能引发异常的代码才需要放在try语句中。有时候,有一些仅在try代码块成功执行时才需要运行的代码,这些代码应放在else代码块中。except代码块告诉Python,如果尝试运行try代码块中的代码时引发了指定的异常该怎么 办。
静默失败
在except代码块中写pass语句,这样当错误发生时,不会出现traceback,也没有任何输出。
4、存储数据
模块json让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。你还可以使用json在Python程序之间分享数据。更重要的 是,JSON数据格式并非Python专用的,这让你能够将以JSON格式存储的数据与使用其他编程语言的人分享。这是一种轻便而有用的格式,也易于学习。
注意 JSON(JavaScript Object Notation)格式最初是为JavaScript开发 的,但随后成了一种常见格式,被包括Python在内的众多语言采用。
1 | import json |
函数json.dump()接受两个实参:要存储的数据,以及可用于存储数据的文件对象。
先导入模块json ,再创建一个数字列表。在❶处,指定了要将该数字列表存储到哪个文件中。通常使用文件扩展名.json来指出文件存储的数据为JSON格式。接下来, 以写入模式打开这个文件,让json能够将数据写入其中(见❷)。在❸处,使用函数json.dump()将数字列表存储到文件numbers.json中。
1 | import json |
在❶处,确保读取的是前面写入的文件。这次以读取方式打开该文件,因为Python只需要读取它(见❷)。在❸处,使用函数json.load()加载存储在numbers.json中的信息,并将其赋给变量numbers 。