• 6. Python 异常、模块与包


    1. 异常

    1.1 了解异常

    当检测到一个错误时,Python 解释器就无法继续执行,出现一些错误的提示,这就是 “异常”,也就是 Bug。

    1.2 异常的捕获方法

    捕获异常的作用在于:提前假设某处会出现异常,提前做好准备。当真的出现异常的时候,可以有后续手段。

    1.2.1 捕获所有异常

    方式1:

    try:
    	可能发生错误的代码
    except:
    	如果出现异常执行的代码
    
    • 1
    • 2
    • 3
    • 4

    【例】尝试以 r 模式打开文件,如果文件不存在,则以 w 方式打开。

    try:
        f = open("D:/abc.txt", "r", encoding="utf-8")
    except:
        print("出现异常,将以'w'模式打开文件")
        f = open("D:/abc.txt", "w", encoding="utf-8")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方式2(一般用这种):
    在 except 后面,加上异常类型 Exception。
    【例】

    try:
        print(1 / 0)
    except Exception as e:
        print(f"出现了{e}异常")#出现了division by zero异常
    
    • 1
    • 2
    • 3
    • 4

    1.2.2 捕获指定异常

    基本语法:

    try:
        print(1 / 0)
    except ZeroDivisionError as e:
        print(f"出现了{e}异常")#出现了division by zero异常
    
    • 1
    • 2
    • 3
    • 4

    注意事项
    ① 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
    ② 一般 try 下方只放一行尝试执行的代码。
    ③ 如果不知道 except 后面的异常名写什么,可以先不捕获,从控制台看一下。如上面代码中的,可以直接运行 print(1/0),从控制台得到异常名称:
    在这里插入图片描述

    1.2.3 捕获多个异常

    当捕获多个异常时,可以把异常类型的名字统一放在元组中,放到 except 后。

    try:
        print(name)
    except (ZeroDivisionError, NameError) as e:
        print(f"出现了{e}异常")
    
    • 1
    • 2
    • 3
    • 4

    输出结果:

    出现了name 'name' is not defined异常
    
    • 1

    1.2.4 异常 else(可选)

    else:表示的是如果没有异常要执行的代码,else 部分也可以不写。

    try:
    	print(1)
    except Exception as e:
    	print(e)
    else:
        print("我是else,是没有异常的时候执行的代码")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果:

    1
    我是else,是没有异常的时候执行的代码
    
    • 1
    • 2

    1.2.5 异常 finally(可选)

    finally:表示的是无论是否异常都要执行的代码,例如:关闭文件。finally 部分也可以不写

    【例】以r模式打开 aaa.txt 文件,若文件不存在就创建以 w 模式打开的新文件。

    try:
        f = open("D:/aaa.txt", "r", encoding="utf-8")
    except Exception as e:
        print("aaa.txt不存在,创建以w模式打开的新文件")
        f = open("D:/aaa.txt", "w", encoding="utf-8")
    else:
        print("未出现异常")
    finally:
        print("不管是否出现异常,都执行finally")
        f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:

    aaa.txt不存在,创建以w模式打开的新文件
    不管是否出现异常,都执行finally
    
    • 1
    • 2

    1.2.6 细节问题

    出现异常时,try 块中,异常后面剩余的语句不会执行。

    try:
        print("1111")
        print(1/0)
        print("2222")#不会执行
    
    except Exception as e:
        print("出现异常")
    
    print("程序结束")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出结果:

    1111
    出现异常
    程序结束
    
    • 1
    • 2
    • 3

    1.2.7 捕获异常的语法总结

    try:
    	可能要发生异常的语句
    except[异常 as 别名]:
    	出现异常的准备手段
    [else:]
    	未出现异常时应做的事情
    [final1y:]
    	不管出不出现异常都会做的事情
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.3 异常的传递

    若 main、func1、func2 有如下调用关系:
    在这里插入图片描述

    每个函数内部出现异常时,都有两种处理方式:① 自己捕获处理;② 向调用者传递异常。
    当函数 func2 中发生异常,并且没有捕获处理这个异常的时候,异常会传递到函数func1;
    当 func1 也没有捕获处理这个异常的时候,异常会传递到 main 函数,若 main 函数捕获处理这个异常,异常就得到处理,否则报错。这就是异常的传递性。

    def func2():
        print("func2开始执行")
        print(1 / 0)  # 发生异常
        print("func2结束执行")
    
    def func1():
        print("func1开始执行")
        func2()
        print("func1结束执行")
    
    def main():
        try:
            func1()
        except Exception as e:
            print("出现了异常")
    
    main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    输出结果:

    func1开始执行
    func2开始执行
    出现了异常
    
    • 1
    • 2
    • 3

    2. 模块

    2.1 模块引入

    什么是模块
      模块(Module)是一个 Python 文件,以.py结尾。模块能定义函数、类和变量,也能包含可执行的代码。
    .
    模块的作用
      Python 中有很多各种不同的模块,每一个模块都可以快速地实现一些功能,比如:实现与时间相关的功能可以使用 time 模块。
      可以认为一个模块就是一个工具包,每一个工具包中都有各种不同的工具,实现各种不同的功能。
      在代码中,可以通过 Ctrl + B 定位到模块对应的 Python 文件或具体的函数、类、变量等。

    2.2 模块的导入方式

      模块在使用前需要先导入,模块的导入一般写在代码文件的开头位置。导入的语法如下:

    [from 模块名] import [模块||变量|函数|*] [as 别名]
    
    • 1

    常用的组合形式如:

    • import 模块名
    • from 模块名 import 类、变量、方法等
    • from 模块名 import *
    • import 模块名 as 别名
    • from 模块名 import 功能名 as 别名

    (1) import 模块名

    基本语法:

    import 模块名
    import 模块名1, 模块名2
    模块名.功能名()
    
    • 1
    • 2
    • 3

    【例】导入 time 模块

    # 导入时间模块
    import time
    print("开始")
    # 让程序睡眠5秒(阻塞)
    time.sleep(5)
    print("结束")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2) from 模块名 import 功能名

    基本语法:

    from 模块名 import 功能名
    功能名()
    
    • 1
    • 2

    【例】导入time 模块中的 sleep 方法

    #只导入时间模块中的sleep方法
    from time import sleep
    print("开始")
    #让程序睡眠5秒(阻塞)
    sleep(5)
    print("结束")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3) from 模块名 import *

    基本语法:

    from 模块名 import *
    功能名()
    
    • 1
    • 2

    【例】导入time 模块中所有的方法

    #导入时间模块中所有的方法
    from time import *
    print("开始")
    #让程序睡眠5秒(阻塞)
    sleep(5)
    print("结束")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (4) as 定义别名

    基本语法:

    # 模块定义别名
    import 模块名 as 别名
    # 功能定义别名
    from 模块名 import 功能 as 别名
    
    • 1
    • 2
    • 3
    • 4

    【例】

    # 模块别名
    import time as tt
    tt.sleep(2)
    print('hello')
    # 功能别名
    from time import sleep as sl
    sl(2)
    print('hello')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3 自定义模块

      Python 中已经实现了很多的模块,不过有时候需要一些个性化的模块,这时就可以通过自定义模块实现,也就是自己制作一个模块。

    自定义 my_module 模块:

    # test函数在my_module.py文件中
    def test(a, b):
        return a + b
    
    • 1
    • 2
    • 3

    使用方式 1:

    #想要调用的函数所在的文件名,要符合标识符命名规则
    import my_module 
    res = my_module.test(1, 2)
    print(res)#输出3
    
    • 1
    • 2
    • 3
    • 4

    使用方式 2:

    from my_module import test
    res = test(1, 2)
    print(res)#输出3
    
    • 1
    • 2
    • 3

    当导入多个模块,且模块内有同名功能时,若调用这个同名功能,调用到的是后面导入模块的功能。

    #模块1
    def test(a, b):
    print(a + b)
    
    • 1
    • 2
    • 3
    #模块2
    def test(a, b):
    print(a - b)
    
    • 1
    • 2
    • 3
    #导入模块和调用功能
    from my_module1 import test#在pycharm中是灰色,表示没用
    from my_module2 import test
    #模块2的test函数将模块1的test函数覆盖了
    #所以,test函数是模块2中的函数
    test(1, 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4 测试模块

    当编写完一个模块后,通常要进行测试。如: 在 my_module1.py 中添加测试代码test(1, 1),从而右键运行 my_module1.py 时,能够测试 test 函数。

    # my_module1.py
    def test(a, b):
    	print(a + b)
    test(1,1)
    
    • 1
    • 2
    • 3
    • 4

    此时,若在其他文件中直接 import my_module1,就会直接执行 test(1,1),输出 3。

    import my_module1 #输出3
    
    • 1

    这是不合理的,但又不想删除 my_module1.py 中的测试代码 test(1,1)。这时就可以把测试代码写入if __name__ == '__main__':中。

    def test(a, b):
        print(a + b)
    
    if __name__ == '__main__':
        test(1, 2)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这样,直接右键执行 my_module1.py 进行测试时,会输出 test(1,1) 的执行结果; 而 import my_module1 时,就不会再执行 test(1,1)。

    2.5 __all__ 变量

    __all__ 变量可以控制 import * 的时候哪些功能可以被导入。(all 的两侧各有 2 个下划线 “_”)
    如果一个模块文件中有__all__ 变量,当使用 from xxx import * 导入时,只能导入这个列表中的元素。
    在这里插入图片描述
    __all__ 变量只能限制 from my_module1 import *,还是可以通过 from my_module1 import test_B 导入 test_B 函数的。而且 import my_module1 也不受限制,可以通过 my_module1.test_B() 调用 test_B 函数。

    3. Python 包

    3.1 自定义包

    基于 Python 模块,就可以在编写代码时,导入外部代码来丰富功能。
    但是,若 Python 的模块太多,就可能造成混乱,这时就可以用包来管理。

    什么是Python包
    包就是一个文件夹,其中包含一个__init__.py 文件,也可以包含多个模块文件。包的本质依然是模块。
    一个文件夹中,若有__init__.py 文件,就是包;否则就是普通文件夹。
    在这里插入图片描述
    自定义 Python 包
    ① 新建包 my_package
    ② 新建包内模块:my_module1 和 my_module2
    ③ 在模块中写入代码
    Pycharm 中的具体操作:[New]➡[Python Package]➡输入包名➡[OK]➡新建功能模块

    注意:新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为。

    在这里插入图片描述

    导入自定义的包

    方式 1:

    # test.py文件
    import my_package.my_module1
    import my_package.my_module2
    my_package.my_module1.info_print1()#my_module1
    my_package.my_module2.info_print2()#my_module2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方式 2:

    # test.py文件
    from my_package import my_module1
    from my_package import my_module2
    my_module1.info_print1()#my_module1
    my_module2.info_print2()#my_module2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方式3:

    # test.py文件
    from my_package.my_module1 import info_print1
    from my_package.my_module2 import info_print2
    info_print1()
    info_print2()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    __all__ 控制导入模块
    __init__.py 文件中添加__all__ = [],可以指定允许导入的模块。
    __all__ 针对的是 “from… import*” 这种方式,对其他指定确切导入模块或功能的方式无效。

    # __init__.py文件
    __all__ = ["my_module1"]
    
    • 1
    • 2
    # test.py文件
    from my_package import *
    my_module1.info_print1()
    # my_module2.info_print2()#不能用
    
    • 1
    • 2
    • 3
    • 4

    3.2 安装第三方包

    什么是第三方包
      包可以包含一堆的 Python 模块,而每个模块又内含许多的功能。所以可以认为:一个包,就是一堆同类型功能的集合体。
      在 Python 中,有许多第三方包(非Python官方),可以极大的帮助我们提高开发效率,如:

    • 科学计算中常用的:numpy包
    • 数据分析中常用的:pandas包
    • 大数据计算中常用的:pyspark、apache-flink包
    • 图形可视化常用的:matplotlib、pyecharts
    • 人工智能常用的:tensorflow 等

      这些第三方的包,极大的丰富了 Python 的生态,提高了开发效率。
      但是由于是第三方,所以 Python 没有内置,所以我们需要安装它们才可以导入使用。

    如何安装第三方包

    方式 1:在命令提示符内:
    pip install 包名称(速度慢)
    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称(速度快,推荐)
    检验是否安装成功:
    在这里插入图片描述

    方式 2:在 PyCharm 中:

    (1)点击PyCharm 右下角解释器设置
    在这里插入图片描述
    (2)(下面展示的是一些已经安装过的包)点击加号。
    在这里插入图片描述
    (3)搜索要下载的包,以 tensorflow 为例,用清华源,点击安装。稍等一下就安装好了。
    在这里插入图片描述
    (4)验证是否安装成功
    在(2)中的列表内就能看到已经安装过的包。

    【例】创建一个自定义包,名称为:my_utils,在包内提供 2 个模块:

    • str_util.py(字符串相关工具,内含:)
      str_reverse(s),接受传入字符串,将字符串反转返回。
      substr(s, x, y),按照下标 x 和 y ,对字符串进行切片。
    • file_util.py(文件处理相关工具,内含:)
      print_file_info(file_name),接收传入文件的路径,打印文件的全部内容,如文件不存在则捕获异常,输出提示信息,通过 finally 关闭文件对象。
      append_to_file(file_name, data),接收文件路径以及传入数据,将数据追加写入到文件中。

    构建出包后,尝试着用一用自己编写的工具包。

    # str_util.py
    def str_reverse(s):
        return s[::-1]
    
    def substr(s,x,y):
        return s[:x], s[x:y], s[y:]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # file_util.py
    def print_file_info(file_name):
        f = None
        try:
            f = open(file_name, "r", encoding="utf-8")
            for line in f:
                print(line)
        except Exception as e:
            print("文件不存在")
        finally:
            if f:#变量赋值不成功,没有默认值?
                f.close()
    
    def append_to_file(file_name,data):
        f = open(file_name, "a", encoding="utf-8")
        f.write(data)
        f.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    # test.py
    from my_utils import str_util, file_util
    print(str_util.str_reverse("hello"))
    str1, str2, str3 = str_util.substr("0123456789", 3, 7)
    print(str1, str2, str3)
    print("====================================")
    file_util.print_file_info("D:/abc.txt")
    file_util.append_to_file("D:/abc.txt", "新添加的内容")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    Redis系列18:过期数据的删除策略
    易优cms小程序常见问题
    C++:C++编程语言学习之数据类型&常量&变量的简介、案例应用之详细攻略
    java参数传值
    开发一款教育app需要具备哪些功能
    GDPU 数据结构 天码行空8
    Android 12(S) 图像显示系统 - BufferQueue的工作流程(十一)
    spdlog C++日志管理 安装和下载
    GPT4应用讲解,如何获取ChatGPT账号
    新零售数智化转型,需要怎样的数据底座?
  • 原文地址:https://blog.csdn.net/qq_44378854/article/details/126524519