python语言基础(四)--文件和异常

一、文件

(一)、文件概述

概述

我们所熟知的操作系统, 例如: Windows, MacOS, Linux 都是文件操作系统, 它们都是通过 文件 来管理数据的.

基本操作步骤

  • 打开文件.

  • 读取数据 或者 写入数据 或者 追加数据.

  • 关闭文件.

涉及函数

open(文件路径, 模式, 码表)
    参1: 文件路径, 可以写绝对路径, 也可以写相对路径.
        绝对路径: 固定的, 写死的路径, 以盘符开头.   d:/data/1.txt
        相对路径: 一般是相对于当前项目的路径来讲的.
            例如: 你写了 1.txt  这是一个相对路径, 它对应的绝对路径为: 当前项目的路径 + 1.txt, 具体如下:
                D:\workspace\pythonProject\practice\1.txt
    参2: 模式
        r:  只读, 默认模式, 可以读取 字符.  '你好'
        rb: 只读, 以二进制形式读取数据, 例如: 图片, 音频, 视频, 文本...
        w: 只写(覆盖写入), 可以操作 字符.
        wb: 只写(覆盖写入), 操作的是 字节.
        a: 追加写入, 可以操作 字符.
        ab: 追加写入, 操作的是 字节.

    参3: 码表
        码表 = 字符 + 其对应的int类型的整数, 例如: 'a' => 97, 'A' => 65, '0' => 48
        
       
read(num)       一次读取num个字节的数据, 不写num, 则一次性读取全部数据.  如果文件不存在就报错.
readlines()     一次性读取所有的行, 并把每行数据封装成1个字符串, 然后整体放到1个列表中, 即: [第一行数据, 第二行数据...]
readline()      一次读取一行数据, 并封装成字符串, 然后返回.
write(数据)			一次往文件中写入指定的内容, 不能是列表, 元组等多个值...
writelines(容器类型)   一次往文件中写入多个值, 必须是: 容器类型.

close()         关闭文件, 释放资源.

注意:

  • 上述的模式中, r, w, a 都是可以操作字符的, 即: 可以结合码表 encoding 一起使用.

  • 上述的模式中, rb, wb, ab都是操作二进制的, 所以不能结合 encoding参数 一起使用.

  • 码表 就是描述 字符 和 整数之间的关系的, 例如: ASCII, GBK, utf-8…

  • 在gbk码表中, 1个中文占2个字节, 在utf-8码表中, 1个中文占3个字节.

  • 数字, 字母, 特殊符号无论在什么码表中, 都只占 1个字节.

(二)、读

1、read()

格式

read(num)       一次读取num个字节的数据, 不写num, 则一次性读取全部数据.  如果文件不存在就报错

例如

# 1. 打开文件.
# 相对路径.
f = open('1.txt', 'r')

# 绝对路径
# 写法1: r''   取消\的特殊含义
# f = open(r'D:\workspace\pythonProject\practice\1.txt', 'r')
# 写法2: \\ => \
# f = open('D:\\workspace\\pythonProject\\practice\\1.txt', 'r')
# 写法3: 直接写 1个 /
# f = open('D:/workspace/pythonProject/practice/1.txt', 'r')

# 如果数据源文件不存在, 就会报错.
# f = open('2.txt', 'r')

# ./代表当前项目的路径, 可以省略不写.
# f = open('./data/2.txt', 'r')
f = open('data/2.txt', 'r')

# 2. 读取文件.
# data = f.read()     # 不写长度, 一次性读取所有的内容.
# data = f.read(2)      # 写长度, 则一次读取 2个字节.
# data = f.read(3)      # 写长度, 则一次读取 3个字节.
data = f.read(10)       # 写长度, 则一次读取 10个字节, 如果文件内容不足10个字节, 则读取全部内容.
print(data)

# 文件数据已经读取完毕, 如果继续读取, 则: 返回 ''
data2 = f.read(3)
print(data2)

# 3. 关闭文件.
f.close()

2、readline()

格式

readline()      一次读取一行数据, 并封装成字符串, 然后返回.

例如

# 1. 打开文件.
f = open('1.txt', 'r')

# 2. 读取文件数据.
# 方式1: readline(), 一次读取一行, 分解版写法.
line1 = f.readline()    # 'abc\n'
line2 = f.readline()    # 'def\n'
line3 = f.readline()    # 'g\n'
line4 = f.readline()    # ''

print(f'line1: {line1}', end='')
print(f'line2: {line2}', end='')
print(f'line3: {line3}', end='')
print(f'line4: {line4}', end='')

# 方式2: readline(), 一次读取一行, 合并版写法.
while True:
    # 一次读取一行数据.
    line = f.readline()
    # 判断读取到的数据是否为空, 如果为空, 说明文件内容读取完毕, 结束循环即可.
    # if len(line) == 0:
    # if not line:              # 0, None, '' => False, 其它 => True
    # if bool(line) == False:   # 0, None, '' => False, 其它 => True
    if line == '':
        break
    # 走到这里, 说明读取到数据了.
    print(f'line: {line}', end='')

# 3. 关闭文件.
f.close()

3、readlines()

格式

readlines()     一次性读取所有的行, 并把每行数据封装成1个字符串, 然后整体放到1个列表中,: [第一行数据, 第二行数据...]

例如

# 1. 打开文件.
f = open('1.txt', 'r')

# 2. 读取文件数据.
# 方式1: readlines(): 一次读取所有行, 每行封装成字符串, 然后整体封装成列表.
lines = f.readlines()
print(lines)        # ['abc\n', 'def\n', 'g\n']
print(type(lines))  # <class 'list'>

# 3. 关闭文件.
f.close()

4、读取中文

注意

  • 中文在gbk码表(针对于国内)中占 2 个字节, 在utf-8码表(针对于国际, 也叫: 万国码, 统一码)中占 3个字节.

  • 英文字母, 数字, 特殊符号无论在什么码表中, 都只占 1个字节.

  • 码表 = 字符 + 字符对应的整数, 码表就是描述 字符 及其 对应的整数之间的 关系的.

例如

# 1. 打开文件.
# f = open('1.txt', 'r')      # 默认的码表是: gbk码表.
# f = open('1.txt', 'r', encoding='gbk')    # 效果同上.

# 码表名可以写 utf-8 或者 utf8, 建议写: utf-8
# f = open('1.txt', 'r', encoding='utf8')

# rb: 以 二进制形式 读取文件, 报错, 二进制方式(无论读写), 不能结合 码表(encoding参数)一起用.
# f = open('1.txt', 'rb', encoding='utf8')

# 正确的 二进制 写法.
f = open('1.txt', 'rb')

# 2. 读取文件数据.
lines = f.readlines()
print(lines)

# 3. 关闭文件.
f.close()

(三)、写

1、write()

格式

write(数据)           一次往文件中写入指定的内容, 不能是列表, 元组等多个值...

例如

# 场景1: 字符方式 覆盖写入, 或者追加写入, 即: w, a 模式演示.
# 1. 打开文件.
# 只读模式, 如果文件不存在, 就报错.
# f = open('2.txt', 'r')

# 覆盖写入模式 或者 追加写入模式, 如果目的地文件不存在(前提: 父目录存在), 则会自动创建.
# f = open('2.txt', 'w')
# f = open('2.txt', 'a')

# 父目录存在
# f = open('./data/1.txt', 'w')   # 覆盖写入.
# f = open('./data/1.txt', 'a')   # 追加写入.

f = open('./data/1.txt', 'w', encoding='utf-8')   # 覆盖写入, 支持中文.

# 父目录不存在的情况.
# f = open('aa/bb/cc/2.txt', 'w')     # FileNotFoundError, 文件不存在.

# 2. 往文件中写数据.
f.write('abc\n')
f.write('def\n')
f.write('g\n')
f.write('好好学习!\n')  # 如果要写中文, 记得加上 encoding='utf-8'

# 3. 关闭文件.
f.close()



# 场景2: 字节方式 覆盖写入, 或者追加写入, 即: wb, ab 模式演示.
# 1. 打开文件.
# f = open('./data/1.txt', 'wb')   # 覆盖写入, 二进制形式
f = open('./data/1.txt', 'ab')   # 追加写入, 二进制形式

# 2. 往文件中写数据.
f.write(b'abc\n')
f.write(b'def\n')
f.write(b'g\n')
f.write(b'\xe5\xa5\xbd\xe5\xa5\xbd\xe5\xad\xa6\xe4\xb9\xa0!\n')  # 如果要写中文, 记得加上 encoding='utf-8'

# 3. 关闭文件.
f.close()

2、writelines()

格式

writelines(容器类型)   一次往文件中写入多个值, 必须是: 容器类型

例如

# 场景1: writelines() 一次写多行.
f = open('data/1.txt', 'w', encoding='utf-8')

# writelines() 要的是容器类型.
# f.writelines(['故人西辞富士康, \n', '为学技术到蓝翔!\n', '蓝翔毕业包分配,\n', '居然还是富士康!\n'])
f.writelines(('故人西辞富士康, \n', '为学技术到蓝翔!\n', '蓝翔毕业包分配,\n', '居然还是富士康!\n'))
f.writelines('abc')

# 如果操作字典, 则只写入: 键.
# f.writelines({'name': '张三', 'age': 23, 'gender': '男'})

# 报错: writelines()接收的是: 容器类型.
# f.writelines(10)
f.close()

注意:

  • 从打开 到 关闭, 这是一个完整的动作, 其内部是不会不断覆盖的.

  • 我们用 read(), readline() + write() 这种方式较多.
    而 readlines() + writelines() 这种方式相对较少, 它比较适合 小文件的操作.

(四)、编解码

概述

编码: 把我们看得懂的数据 => 我们看不懂的数据, 这个动作叫: 编码.
解码: 把我们看不懂的数据 => 我们看得懂的数据, 这个动作叫: 解码.

注意

  • 中文 => gbk(2个字节), UTF-8(3个字节), 数字,字母,特殊符号 => 无论什么码表, 都只占 1个 字节.

  • 只要出现乱码问题了, 原因只有1个: 编解码不一致.

  • 编解码涉及到的函数:
    encode(): 编码.
    decode(): 解码.

  • 二进制的特殊写法, b’内容’, 只针对于 数字, 字母, 特殊符号有效, 针对于 中文 无效.

例如

# 1. 演示 编码.
# s1 = 'abcXYZ123!@#'
s1 = 'aX1!你好'

# 具体的编码动作.
bys1 = s1.encode()                  # 默认码表(utf-8).  bys => bytes, 字节列表.
bys2 = s1.encode(encoding='gbk')    # 指定码表 => gbk
bys3 = s1.encode(encoding='utf-8')  # 指定码表 => utf-8

print(f'bys1: {bys1}')  # b'aX1!\xe4\xbd\xa0\xe5\xa5\xbd'
print(f'bys2: {bys2}')  # b'aX1!\xc4\xe3\xba\xc3'
print(f'bys3: {bys3}')  # b'aX1!\xe4\xbd\xa0\xe5\xa5\xbd'

# 打印类型
print(type(bys1))   # <class 'bytes'>
print(type(bys2))   # <class 'bytes'>
print(type(bys3))   # <class 'bytes'>
print('-' * 30)

# 2. 演示 解码
s2 = bys1.decode()                  # 默认码表(utf-8).
s3 = bys1.decode(encoding='gbk')    # 指定gbk码表
s4 = bys1.decode(encoding='utf-8')  # 指定utf-8码表

print(f's2: {s2}')
print(f's3: {s3}')  # 乱码, 因为: 编解码不一致.
print(f's4: {s4}')

print(type(s2))
print(type(s3))
print(type(s4))
print('-' * 30)

# 3. 演示 二进制的特殊写法.
bys4 = b'abcXYZ123!@#'
# bys4 = b'abcXYZ123!@#你好'    # 报错, b'内容' 只针对于 数字, 字母, 特殊符号有效, 针对于 中文 无效.
print(f'bys4: {bys4}')  # b'abc'
print(type(bys4))       # <class 'bytes'>

(五)拷贝与备份文件

1、拷贝文件

# 需求1: 把 data目录下的a.jpg => data目录下的b.jpg文件中.
# 1. 封装数据源文件, 获取: 文件对象.
src_f = open('data/a.jpg', 'rb')
# src_f = open('data/1.txt', 'rb')
# 2. 封装目的地文件, 获取: 文件对象.
dest_f = open('data/b.jpg', 'wb')
# dest_f = open('data/2.txt', 'wb')
# 3. 具体的拷贝动作.
# 思路3: 循环读取, 一次读取指定数量的数据, 然后写出到目的地文件中.
while True:
    # 一次读取指定数量的数据, 一般是: 1024 的整数倍.
    # bit(比特位), byte, kb, mb, gb, tb, pb, eb, zb, yb, bb, nb, db
    data = src_f.read(8192)   # 一次读取 8KB
    # 判断读取到的数据是否为空, 如果为空, 说明文件读完了, 结束循环即可.
    if not data:    # '' => False
        break
    # 走这里, 说明读取到数据了, 就写到目的地文件中.
    dest_f.write(data)

# 4. 释放资源.
src_f.close()
dest_f.close()

2、备份文件

# 方式1: 分解版写法.
# 1. 提示用户录入文件名.
file_name = input("请输入文件名: ")

# 2. 判断用户录入的文件名是否合法.
idx = file_name.rfind(".")        # 找.的最后一次出现的位置.
if idx <= 0:        # abc => -1,  .txt => 0
    print('文件名不合法, 程序结束!')
else:
    # 3. 走到这里, 说明文件名合法, 就拼接: 目的地文件名.
    dest_file_name = file_name[:idx] + '[备份]' + file_name[idx:]
    # print(dest_file_name)

    # 4. 具体的拷贝动作.
    src_f = open(file_name, 'rb')
    dest_f = open(dest_file_name, 'wb')
    while True:
        data = src_f.read(8192)
        if not data:
            break   # 走这里, 说明文件内容读取完毕.
        # 走这里, 说明有文件, 就写出
        dest_f.write(data)

    # 5. 释放资源
    src_f.close()
    dest_f.close()

    # 6. 提示用户.
    print('拷贝成功!')
 



# 方式2: 函数版.  抽取函数的快捷键 => ctrl + alt + m
def copy_file(src_file_name, dest_file_name):
    """
    自定义函数, 完成: 文件备份
    :param src_file_name: 数据源文件名
    :param dest_file_name: 目的地文件名
    :return: 无
    """
    # 1. 封装数据源 和 目的地文件.
    src_f = open(src_file_name, 'rb')
    dest_f = open(dest_file_name, 'wb')
    # 2. 具体的拷贝动作
    while True:
        data = src_f.read(8192)
        if not data:
            break  # 走这里, 说明文件内容读取完毕.
        # 走这里, 说明有文件, 就写出
        dest_f.write(data)
    # 3. 释放资源
    src_f.close()
    dest_f.close()

(六)with…open…

概述

是用来简化 文件操作的, 可以帮助我们自动释放资源

格式

with open(文件路径, 模式, 码表) as 别名:
    正常读文件数据 或者 写数据到文件

细节

  • with open()语法 会在其内部的代码执行完毕后, 自动释放资源, 无需手动释放

  • with open()语法的本质是 一个上下文管理器对象

例如

# 利用with...open...来简化上面的拷贝文件
# 1. 封装数据源文件, 目的地文件,  获取: 文件对象.
with open('data/a.jpg', 'rb') as src_f, open('data/b.jpg', 'wb') as dest_f:
    # 2. 具体的拷贝动作.
    while True:
        # 一次读取指定数量的数据, 一般是: 1024 的整数倍.
        data = src_f.read(8192)   # 一次读取 8KB
        # 判断读取到的数据是否为空, 如果为空, 说明文件读完了, 结束循环即可.
        if not data:    # '' => False
            break
        # 走这里, 说明读取到数据了, 就写到目的地文件中.
        dest_f.write(data)

# with open语法, 会在其内部的代码执行完毕后, 自动释放资源.

(七)os模块

概述

全称叫Operating System, 也叫: 系统模块, 主要是操作 文件, 文件夹, 路径等的

常用函数

getcwd()    获取当前工作目录, 即: 你写的相对路径, 都是相对于这个路径来讲的. get current work directory
chdir()     改变工作路径, 即: 相对路径以后就是相对于这个路径来讲的.
listdir()   查看当前目录下, 所有的子级(不包括子级的子级)
mkdir()     创建目录的, 如果存在就报错, 不存在就创建.
rename()    修改文件的名字.
remove()    删除指定的文件.

例如

# 导包
import os

# 演示os模块常用的函数.
# 1. 获取当前工作目录, 即: 你写的相对路径, 都是相对于这个路径来讲的.
print(os.getcwd())  # D:\workspace\pythonProject\practice

# 2. 设置当前的工作空间为指定的目录.
os.chdir('d:\\data\\')
os.chdir('d:/data/')

# 重新查看当前的工作空间.
print(os.getcwd())

# 读取文件内容.
f = open('1.txt', 'r', encoding='utf-8')
print(f.read())
f.close()

# 3. 查看当前目录下所有的文件(不包括子级的子级)
print(os.listdir('./'))     # 获取当前目录下所有的文件(不包括子级的子集)

# 4. 在指定目录下创建 子目录.
os.mkdir('./data/cheers')  # make directory: 制作目录, 该目录必须:不存在.

# 5. 改名.
os.rename('data/cheers', 'data/cheers_new')

# 6. 删除文件的.
os.remove('data/cheers_new/a.jpg')

(八)shutil模块

概述

它里边的函数, 大多数是和 文件(文件夹)相关的, 且大多数的函数 底层都支持递归.
例如: copyfile() 就可以实现 拷贝文件.

例如

# 扩展: shutil 模块.
import shutil

# shutil模块的 copyfile()函数可以实现: 拷贝文件.
shutil.copyfile('data/1.txt', 'data/2.txt')
shutil.copyfile('data/a.jpg', 'data/b.jpg')

二、异常

我们把程序中出现的所有非正常情况, 统称为: 异常. 俗称叫: Bug.程序会将异常的类型, 产生的原因, 以及异常的位置, 打印到控制台上.并终止程序的执行

(一)、捕获异常

概述

它指的是 try.except.finally 这个语法, 即: 手动处理异常

特点

手动处理之后, 程序会继续向下执行

格式

try:
    里边写可能出问题的代码
except:
    如果出问题了, 这里写的是 处理方式
  • 先执行try中的内容, 看有无问题.
  • 有问题, 则会立即跳转到 except语句中 执行.
  • 无问题, 则不会执行 except中的内容.
  • 无论是否有问题, 处理之后, 程序都会自动向下执行.

例如

# 需求: 尝试去读取 1.txt 文件中的数据, 如果文件不存在, 我们就创建.
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
    src_f = open('1.txt', 'r')  # 这行代码有Bug
    print('----- try 2 -----')
    print(src_f)
except:
    # 这里写的是, 出问题后的解决方案
    # print('哎呀, 程序出问题了!')
    # 走这里, 说明文件不存在, 我们就创建它.
    src_f = open('1.txt', 'w')
    print('----- except -----')

print('看看我执行了吗!')

(二)、捕获指定异常

概述

它指的是 try.except.finally 这个语法, 即: 手动处理异常

特点

手动处理之后, 程序会继续向下执行

格式

try:
    里边写可能出问题的代码
except [Exception as e]:                          # 这里的[]表示 可选
    如果出问题了, 这里写的是 处理方式
  • 先执行try中的内容, 看有无问题.

  • 有问题, 则会立即跳转到 except语句中 执行.

  • 无问题, 则不会执行 except中的内容.

  • 无论是否有问题, 处理之后, 程序都会自动向下执行.

例如

# 你可能会遇到的一些异常.
# print(10 // 0)            # 除数不能为 0, ZeroDivisionError

# src_f = open('1.txt', 'r')  # 文件不存在, FileNotFoundError
# print(src_f)


# 需求: 尝试去读取 1.txt 文件中的数据, 如果文件不存在, 我们就创建.
# 场景1: 捕获指定的异常.
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
     src_f = open('1.txt', 'r')  # 这行代码有Bug
    print('----- try 2 -----')
except FileNotFoundError:
    # 这里写的是, 出问题后的解决方案
    print('----- except 1 -----')
    src_f = open('1.txt', 'w')
    print('----- except 2 -----')


# 场景2: 捕获异常时, 异常的类型 和 异常出现的类型不匹配, 则: 捕获不到该异常.
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
    src_f = open('1.txt', 'r')  # 这行代码有Bug
    print('----- try 2 -----')
except ZeroDivisionError:
    # 这里写的是, 出问题后的解决方案
    print('----- except 1 -----')
    src_f = open('1.txt', 'w')
    print('----- except 2 -----')


# 场景3: 捕获多个异常.
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
    # src_f = open('1.txt', 'r')  # 这行代码有Bug
    print(age)
    print(10 // 0)                # 这行代码有Bug
    print('----- try 2 -----')
except (ZeroDivisionError, FileNotFoundError, NameError):
    # 这里写的是, 出问题后的解决方案
    print('哎呀, 程序出错了!')

# 场景4: 捕获所有的异常, 因为Python中的异常类型太多了, 我们不可能逐一编写(除非业务固定, 出的问题也固定), 一般会直接写: Exception
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
    src_f = open('1.txt', 'r')  # 这行代码有Bug
    # print(age)
    # print(10 // 0)                # 这行代码有Bug
    print('----- try 2 -----')
except Exception:           # Exception是所有异常的父类, 即: 它代表所有的异常.
    # 这里写的是, 出问题后的解决方案
    print('哎呀, 程序出错了!')

# 场景5: 打印异常的信息.
try:
    # 这里写的是: 可能出问题的代码
    print('----- try 1 -----')
    # src_f = open('1.txt', 'r')  # 这行代码有Bug
    # print(age)
    print(10 // 0)                # 这行代码有Bug
    print('----- try 2 -----')
except Exception as e:           # Exception是所有异常的父类, 即: 它代表所有的异常.
    # 这里写的是, 出问题后的解决方案
    # print('哎呀, 程序出错了!')
    print(f"程序出错了, 原因是: {e}")


print('看看我执行了吗!')

(三)、捕获异常完整语句

概述

它指的是 try.except.finally 这个语法, 即: 手动处理异常

特点

手动处理之后, 程序会继续向下执行

格式

try:
    里边写可能出问题的代码
except [Exception as e]:                          # 这里的[]表示 可选
    如果出问题了, 这里写的是 处理方式
else:
    如果try中的内容无问题, 则会执行这里.
finally:
    无论try中是否有问题, 都会执行这里的内容.
  • 先执行try中的内容, 看有无问题.

  • 有问题, 则会立即跳转到 except语句中 执行.

  • 无问题, 则try中内容执行完毕后, 会跳转到else中执行.

  • 无论是否有问题, 最终都会执行finally中的内容.

  • 大白话总结:
    程序有问题: try => except => finally
    程序无问题: try => else => finally

例如

# 需求1: 演示 try.except完整格式代码.
try:
    print('----- try 1 -----')
    # print(10 // 0)
    print(10 // 2)
    print('----- try 2 -----')
except Exception as e:
    print(f'程序出问题了, 原因是: {e}')
else:
    print('很开心, 程序没有Bug, 我是else!')
finally:
    print('你们都在说什么, 无论你们执不执行, 我都会执行, 我是finally!')
print('-' * 30)


# 需求2: 加入异常处理后的, 文件备份的代码.
# src_f = open('data/3.jpg', 'rb')
# dest_f = open('data/4.jpg', 'wb')
# while True:
#     data = src_f.read(8192)
#     if not data:
#         break
#     dest_f.write(data)
# src_f.close()
# dest_f.close()

# 标记变量.
flag = False        # False => 文件对象创建失败.  True => 文件对象创建成功.
# global src_f
# global dest_f
try:
    # 可能出问题的代码
    src_f = open('data/1.jpg', 'rb')
    dest_f = open('d ata/4.jpg', 'wb')
    flag = True     # 说明 文件对象创建成功.
except Exception as e:
    # 出问题后的解决方案
    print(f'程序出错了, 原因是: {e}')
else:
    # try中代码无问题, 则会执行这里.
    while True:
        data = src_f.read(8192)
        if not data:
            break
        dest_f.write(data)
finally:
    # 无论try中是否有问题, 最终都会走这里, 一般用于: 释放资源.
    if flag:
        src_f.close()
        dest_f.close()
        print('文件对象已关闭!')
    print('程序执行结束了!')

(四)、异常的传递性

概述

异常是具有传递性的, 如果在某个函数内部有Bug, 且该函数没有处理, 则会传给该函数的调用者来处理.
依次类推, 逐级传递, 直至传到main函数中, 如果还不处理, 程序就会自动处理.
即: 先打印异常的类型, 描述信息, 位置到控制台上, 并终止程序的运行.

细节

  • 如果为了保证所有的异常都被处理了, 我们可以在main函数中对异常做处理.

  • 建议异常越早处理越好, 在哪里发生, 就在哪里处理.

例如

# 需求: 定义函数fun01(), 里边有Bug.  然后由fun02()函数调用fun01()函数, 且在main函数中调用 fun02()函数, 观察会出现什么情况.
# 1. 定义fun01()函数
def fun01():
    print('--- fun01函数 start ---')
    # 情况4: 在fun01函数中, 处理异常.
    try:
        # 有Bug
        print(10 // 0)
    except:
        pass
    print('--- fun01函数 end ---')

# 2. 定义fun02()函数, 调用fun01()函数
def fun02():
    print('--- fun02函数 start ---')
    # 情况3: 在 fun02函数中, 处理异常.
    # 调用fun01()函数
    fun01()
    # try:
    #     fun01()
    # except:
    #     pass
    print('--- fun02函数 end ---')

# 3. 在main函数中, 测试上述的内容.
if __name__ == '__main__':
    # 情况1: 直接调用 fun02()函数, 看看结果是啥.
    fun02()

    # 情况2: 在main中处理异常, 看看结果是啥.
    try:
        # 可能出问题的代码
        fun02()
    except:
        # 出现问题后的解决方案
        pass

    # 情况3: 在fun02()函数中, 处理异常, 看看结果是啥.
    fun02()

    # 情况4: 在fun01()函数中, 处理异常, 看看结果是啥.
    fun02()

    print('看看我执行了吗!')
  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值