# Python3 基础学习笔记 C09

TRHX

2018-11-16

Python3 学习笔记 / 基础学习

字数统计:

3,262字

阅读时长≈

14分

> Python3 基础学习笔记第九章 —— 【文件和异常】

# - 9.1 从文件中读取数据

# - 9.1.1 读取整个文件

有一个文件，包含精确到小数点后30位的圆周率值，且在小数点后每10位处都换行：

    1
    2
    3
    4
    5
    Circumference rate.txt
    ----------
    3.1415926535
      8979323846
      2643383279

以下两个程序将打开并读取这个文件，再将其内容显示到屏幕上：

    1
    2
    3
    4
    5
    #file_reader.py

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

    1
    2
    3
    4
    5
    #file_reader2.py

    contents = open ('Circumference rate.txt')
    print(contents.read())
    contents.close()

函数open()接受一个参数：要打开的文件的名称，Python在当前执行的文件所在的目录中查找指定的文件；关键字with在不再需要访问文件后将其关闭；也可以调用open()和close()来打开和关闭文件，如果使用这种方法，当程序存在bug时，close()语句未执行，文件将不会被关闭；方法read()将读取这个文件的全部内容，并将其作为一个长长的字符串储存在变量contents中，通过打印contents的值，就可以将这个文本文件的全部内容打印出来：

    1
    2
    3
    3.1415926535
      8979323846
      2643383279

输出结果末尾有一空行，这是因为read()到达末尾时返回一个空字符串，而将这个空字符串显示出来就是一个空行，如果要删除末尾的空行，可在print语句中使用rstrip():

    1
    2
    3
    4
    5
    #file_reader.py

    with open('Circumference rate.txt') as file_object:
        contents = file_object.read()
        print(contents.rstrip())

输出结果如下：

    1
    2
    3
    3.1415926535
      8979323846
      2643383279

# - 9.1.2 文件路径

> 相对文件路径：假定程序文件位于python_work文件夹中，程序文件操作的文本文件位于python_work文件夹的子文件夹text_files中，此时可以使用相对文件路径来打开该文本文件，相对文件路径让Python到指定的位置去查找，而该位置是相对于当前运行的程序所在目录的

在Linux和OS X中，相对路径类似于如下：

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

在Windows系统中，文件路径中使用反斜杠（\）而不是斜杠（/）:

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

> 绝对文件路径：不用关心当前运行的程序储存在什么地方，直接将文件在计算机中的准确位置告诉Python，这称为绝对文件路径，绝对路径通常比相对路径更长，因此将其储存在一个变量中，再将变量传递给open()会有所帮助

在Linux和OS X中，绝对路径类似于如下：

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

在Windows系统中，绝对路径类似于如下：

    1
    2
    file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
    with open(file_path) as file_object:

# - 9.1.3 逐行读取

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

    1
    2
    3
    4
    5
    6
    #file_reader.py

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

在文件中每行的末尾都有一个看不见的换行符，而print语句也会加上一个换行符，因此每行末尾都有两个换行符：一个来自文件，一个来自print语句，输出结果如下：

    1
    2
    3
    4
    5
    3.1415926535

      8979323846

      2643383279

要消除这些多余的空白行，可以使用rstrip():

    1
    2
    3
    4
    5
    6
    #file_reader.py

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

输出结果如下：

    1
    2
    3
    3.1415926535
      8979323846
      2643383279

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    #file_reader.py

    filename = 'Circumference rate.txt'
    with open(filename) as file_object:
        lines = file_object.readlines()

    for line in lines:
        print(line.rstrip())

输出结果与文件内容完全一致

# - 9.1.5 使用文件的内容

创建一个字符串，它包含文件中储存的所有数字，且没有任何空格：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #pi_string.py

    filename = 'Circumference rate.txt'
    with open(filename) as file_object:
        lines = file_object.readlines()

    pi_string = ''
    for line in lines:
        pi_string += line.rstrip()

    print(pi_string)
    print(len(pi_string))

打印该字符串以及其长度：

    1
    2
    3.1415926535  8979323846  2643383279
    36

由于原文件每行左边都有空格，我们可以使用strip()而不是rstrip()来删除它：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #pi_string.py

    filename = 'Circumference rate.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.141592653589793238462643383279
    32

> Python中有三个去除头尾字符、空白符的函数，它们依次为:

> strip：用来去除头尾字符、空白符(包括\n、\r、\t、’ ‘，即：换行、回车、制表符、空格)

> lstrip：用来去除开头字符、空白符(包括\n、\r、\t、’ ‘，即：换行、回车、制表符、空格)

> rstrip：用来去除结尾字符、空白符(包括\n、\r、\t、’ ‘，即：换行、回车、制表符、空格)
> 注意：这些函数都只会删除头和尾的字符，中间的不会删除。
> 用法分别为：
> string.strip([chars])
> string.lstrip([chars])
> string.rstrip([chars])
> 参数chars是可选的，当chars为空，默认删除string头尾的空白符(包括\n、\r、\t、’ ‘)
> 当chars不为空时，函数会被chars解成一个个的字符，然后将这些字符去掉
> 它返回的是去除头尾字符(或空白符)的string副本，string本身不会发生改变

# - 9.2 写入文件

将一条简单的消息储存到文件中：

    1
    2
    3
    4
    5
    #write_message.py

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

调用open()时提供了两个实参，第一个实参也是要打开文件的名称，第二个实参（’w’）告诉Python，我们要以写入模式打开这个文件，打开文件时，可指定读取模式（’r’）、写入模式（’w’）、附加模式（’a’）或者让我们能够读取和写入文件的模式（’r+’），如果省略模式实参，则默认以只读模式打开文件

附表：Python读写文件各种模式区别

模式 | 可做操作 | 若文件不存在 | 是否覆盖
--- | --- | --- | ---
r | 打开一个文件用于只读 | 报错 | -
rb | 以二进制格式打开一个文件用于只读 | 报错 | -
r+ | 打开一个文件用于读和写 | 报错 | 是
rb+ | 以二进制格式打开一个文件用于读和写 | 报错 | 是
w | 打开一个文件用于只写 | 创建 | 是
wb | 以二进制格式打开一个文件只用于只写 | 创建 | 是
w+ | 打开一个文件用于读和写 | 创建 | 是
wb+ | 以二进制格式打开一个文件用于读和写 | 创建 | 是
a | 打开一个文件用于追加 | 创建 | 否，追加写
ab | 以二进制格式打开一个文件用于追加 | 创建 | 否，追加写
a+ | 打开一个文件用于读和写 | 创建 | 否，追加写
ab+ | 以二进制格式打开一个文件用于追加 | 创建 | 否，追加写

# - 9.3 使用 try-except 代码块处理异常

当我们尝试将一个数字除以0时，会发生ZeroDivisionError异常：

    1
    2
    3
    4
    5
    >>> print(5/0)
    Traceback (most recent call last):
      File "<pyshell#0>", line 1, in <module>
        print(5/0)
    ZeroDivisionError: division by zero

此时我们可以编写一个try-except代码块来处理该异常：

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

当我们运行该程序时，会出现提示：

    1
    You can't divide by zero!

在try-except代码块中加入else，编写一个只执行除法运算的简单计算器：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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("\nSecond number:")
        if second_number == 'q':
            break
        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
    14
    Give me two numbers,and I'll divide them.
    Enter 'q' to quit.

    First number:45

    Second number:0
    You can't divide by 0!

    First number:36

    Second number:8
    4.5

    First number:q

若不加入try-except代码块，我们在输入0时，程序就会出现异常而崩溃，而try-except代码块很好的解决了这种问题，而且还起到了提示的作用，同样的，try-except代码块也可以处理其他异常，如FileNotFoundError等

# - 9.4 储存数据

# - 9.4.1 使用 json.dump() 和 json.load()

模块json能够将简单的Python数据结构转储到文件中，并在程序再次运行时加载该文件中的数据；编写一个储存一组数字的简短程序，再编写一个将这些数字读取到内存中的程序，第一个程序将使用 json.dump()来储存这组数据，而第二个程序将使用 json.load()。函数 json.dump()接受两个实参：要储存的数据以及可用于储存数据的文件对象：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #number_writer.py

    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，再创建一个数字列表， 通常用文件扩展名.json来指出文件储存的数据为JSON格式，然后以写入模式打开该文件，使用函数json.dump()将数字列表储存到文件numbers.json中，打开该文件，数据的储存格式与Python一样：

    1
    [2, 3, 5, 7, 11, 13]

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

    1
    2
    3
    4
    5
    6
    7
    8
    #number_reader.py

    import json

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

输出结果与number_writer.py中创建的数字列表相同：

    1
    [2, 3, 5, 7, 11, 13]

进阶：在同一个程序中使用 json.dump() 和 json.load()：创建文件username.json储存用户名，从该文件中获取用户名，如果这个文件不存在，就在except代码块中提示用户输入用户名，并将其储存在username.json中：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #remember_me.py

    import json

    #如果以前储存了用户名，就加载它
    #否则就提示用户输入用户名并储存它
    filename = 'numbers.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        username = input("What's 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
    What's your name?TRHX
    We'll remember you when you come back, TRHX!

再次运行程序：

    1
    Welcome back, TRHX!

# - 9.4.2 重构

代码能够正确运行，但可以做进一步的改进——将代码划分为一系列完成具体工作的函数，这样的过程称为重构，重构让代码更清晰、更易于理解、更容易扩展
重构remember_me.py，将大部分逻辑放到一个或者多个函数中：

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #remember_me.py

    import json

    def greet_user():
        #问候用户，并指出其名字
        filename = 'numbers.json'
        try:
            with open(filename) as f_obj:
                username = json.load(f_obj)
        except FileNotFoundError:
            username = input("What's 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 + "!")

    greet_user()

重构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
    25
    26
    27
    28
    #remember_me.py

    import json

    def get_stored_username():
        #如果储存了用户名，就获取它
        filename = 'numbers.json'
        try:
            with open(filename) as f_obj:
                username = json.load(f_obj)
        except FileNotFoundError:
            return None
        else:
            return username

    def greet_user():
        #问候用户，并指出其名字
        username = get_stored_username()
        if username:
            print("Welcome back, " + username + "!")
        else:
            username = input("What's your name?")
            filename = 'username.json'
            with open(filename,'w') as f_obj:
                json.dump(username,f_obj)
                print("We'll remember you when you come back, " + username + "!")

    greet_user()

将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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    #remember_me.py

    import json

    def get_stored_username():
        #如果储存了用户名，就获取它
        filename = 'numbers.json'
        try:
            with open(filename) as f_obj:
                username = json.load(f_obj)
        except FileNotFoundError:
            return None
        else:
            return username

    def get_new_username():
        #提示输入用户名
        username = input("What's 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()

最终版本实现了每个函数只负责单一而清晰的任务，我们在编写程序时也要像这样，要写出清晰而易于维护和扩展的代码

您的喜欢是作者写作最大的动力！❤️

- PayPal
- AliPay
- WeChatPay
- QQPay

Donate

最后更新于 2019年9月24日

文件

异常

###### 上一页

#### 一台电脑使用两个/多个GitHub账号部署两个/多个Hexo博客

###### Hexo Github

###### 下一页

#### Python3 基础学习笔记 C08

###### 类 继承

#### 评论

## ๑۩ﺴ TRHX ﺴ۩๑

本文目录
站内导航

- 所有文章
- 文章归档
- RSS订阅
- 我的友链
- 留言板
- 关于博主

欢迎光临
访客地图
交流群组

QQ 交流群 Telegram 交流群

文章分类

- BLOG
  (4)
- CDN
  (1)
- Hexo
  (9)
- Java
  (1)
- Linux
  (2)
- Markdown
  (2)
- Python3 学习笔记
  (39)
- 基础学习
  (9)
- 学习经验
  (4)
- 爬虫学习
  (18)
- 爬虫实战
  (8)
- VPS
  (1)
- WEB前端
  (2)
- 图床
  (1)

热门标签
12306 58同城 Ajax BLOG Beautiful Soup CDN Coding Pages Deepin Elicpse GitHub Pages Github Github Pages HTTPS Hexo ICP备案 JDBC JS 预加载 Markdown Material X MongoDB MySQL PEP8 PicGo Pygame Python Redis SEO SQL Server 2012 SSR Selenium Ubuntu User-Agent VMware VPS XPath if语句 input()函数 instant.page jsDelivr lxml pyspider requests spfk urllib while循环 主题个性化 代理 公安备案 函数 列表 变量 哔哩哔哩 图床 图形验证码 垃圾 备份 字典 安居客 年终总结 异常 技巧 操作列表 数据类型 文件 文件储存 无界面浏览器 模块 正则表达式 滑动验证码 点触验证码 爬虫 猫眼电影 瓜子二手车 类 继承 编辑器 虎扑论坛 豆瓣电影
最近在听