跳转至

9.1 模块与包——模块基础

内容梗概

本课是"模块与包"章节的第一节,讲解 Python 中模块(module)的基本概念与用法。老师以自写的计算器模块 calc.py 和调用方 cuc.py 为例,在 VS Code 中逐一演示了四种模块导入方式;随后讲解模块被导入时顶层语句会被执行的机制及其在初始化中的用途;接着介绍用内置函数 dir() 查看模块符号表,并重点展开 __name__ 变量的含义与 if __name__ == '__main__': 的测试惯用法;最后引入内置模块 sys,讲解 sys.argv 读取命令行参数、import 不必放在文件开头的细节,以及 sys.platform 等常用属性。

知识点详解

模块的概念(约 00:00–00:30)

  • 其他语言(如 C 语言)通过头文件等机制把项目拆成多个文件互相调用;Python 用"模块和包"实现同样的目的。
  • 模块 ≈ 文件:一个 .py 文件就是一个模块,模块名 = 文件名去掉 .py 后缀。
  • 示例:calc.py 中实现了加减乘除四个简单函数,另一个文件 cuc.py(课件中为 main.py)通过 import calc 导入后即可使用。

模块的四种导入方式(约 00:31–02:25)

  1. import calc —— 整体导入模块,通过 calc.函数名(模块名 + 符号名/item name)访问其中的函数或变量。
  2. import calc as xx —— 起别名,模块名很长时可以"偷懒",用短别名访问。
  3. from calc import add —— 只导入模块中的某个具体符号(函数名),使用时直接写符号名,不再需要 模块名. 前缀。
  4. from calc import add, sub —— 用逗号分隔,一次导入多个符号。
  5. from calc import * —— 星号是通配符,导入模块中所有符号。
  6. 老师说明这几种方式本质区别不大,只是访问形式不同。

导入模块时顶层语句会被执行(约 07:02–10:29)

  • 四种导入方式在执行导入的同时,都会执行被导入模块中**顶格书写(无缩进)的语句**。演示:在 calc.py 顶层写一句打印"模块已导入"的日志,cuc.py 里即使只写 import calc 加 pass,运行时也会打印该语句。
  • 用途:模块的**初始化/配置**工作——无论以哪种方式被导入,都能在导入完成前对自身内容进行配置。
  • 重要提醒(约 09:30):模块顶层的语句应只用于初始化,不能影响使用者。例如在模块里写调试用的 print,导入者会莫名看到额外输出,造成困惑。

模块的符号表与 dir() 函数(约 10:46–14:03)

  • 任何模块都有一个符号表,用内置函数 dir() 可以查看模块包含的所有符号,返回一个列表。
  • 列表中除了自定义的函数名(如四个运算函数),还有许多双下划线包裹的 Python 内置符号。
  • 重点讲了两个:
  • calc.__file__:模块对应的文件路径(字符串)。
  • calc.__name__:模块的名字,即文件名去掉后缀。
  • 其他符号可自行查阅 Python 文档。

__name__ 变量与脚本执行机制(约 14:04–24:06)

  • 每个模块都内置 __name__ 变量。在模块内部访问自己的 __name__ 不需要前缀;访问别的模块的需用 模块名.__name__。
  • 关键机制:用 python 文件名.py 的方式(即"以脚本的方式执行")运行某模块时,该模块内部的 __name__ 会被赋值为 '__main__';被导入时,__name__ 等于模块名本身。
  • 由此可判断项目入口:__name__ == '__main__' 的文件就是当前入口。
  • 典型用途——编写测试用例:开发 calc.py 时想测试 sum 等函数是否正常,可把测试语句写在:
if __name__ == '__main__':
    import sys
    # 测试代码

这样测试代码只在模块被直接以脚本方式运行时执行;被别人 import 时不会执行,避免把测试输出带给使用者。

sys 模块与命令行参数(约 24:07–32:22)

  • 之前程序输入用 input() 等待用户输入;日常命令行程序更常用 python xxx.py 1 2 这种带参数的方式。
  • sys 是 Python 内置模块,sys.argv 是一个列表(list),包含命令行传入的参数:
  • sys.argv[0] 是运行的脚本名(如 ./calc.py);
  • 后续各项是以空格分割的参数,均为字符串,需自行 int() 等转换后再使用。
  • 演示:在 if __name__ == '__main__': 块中读取 sys.argv[1]、sys.argv[2] 转成整数后调用加法函数做测试。
  • 重要细节——import 不必放在文件开头(约 28:17):import 可以写在文件任意位置。把 import sys 放进 if __name__ == '__main__': 块中,是因为 sys 只在测试时用到;若放在文件开头,别人导入本模块时会链式地连带加载 sys,降低执行效率。
  • sys 的其他常用属性(约 30:41):
  • sys.byteorder:字节序(大端/小端);
  • sys.path:模块搜索路径列表(下一节展开);
  • sys.platform:当前操作系统平台('win32'、'linux' 等),可用于跨平台判断,如 if sys.platform == 'win32': 执行 Windows 相应操作;
  • 还可查询 Python 版本、位数(32/64 位)等。

示例与演示

  • calc.py + cuc.py 跨文件调用:calc.py 定义加(sum)、减、乘、除四个函数;cuc.py 依次用四种方式导入并调用,运行结果均正常。
  • 顶层语句执行演示:在 calc.py 顶层写打印"calc imported"的语句,cuc.py 中仅 import calc + pass,运行时该语句被打印;四种导入方式下都会执行。
  • dir(calc) 演示:打印符号表,看到四个自定义函数和若干 __xxx__ 内置符号;再分别打印 calc.__file__(文件路径)和 calc.__name__(模块名)。
  • __name__ 演示:直接运行 python calc.py 时 __name__ 为 '__main__',进入测试分支;运行 python cuc.py(导入 calc)时 calc 的 __name__ 为 'calc',测试分支不执行。
  • 命令行参数演示:python calc.py 1 2,通过 sys.argv 读入 1、2,转为整数后调用加法函数输出结果。

重点与难点

  • 模块顶层语句在导入时必然执行:只写初始化代码,绝不写影响使用者的输出。
  • if __name__ == '__main__': 的语义与用途是本节核心难点:以脚本方式运行时 __name__ 才是 '__main__',被导入时为模块名;用它隔离测试代码。
  • sys.argv 读到的参数都是字符串,argv[0] 是脚本名,容易因忘记类型转换而出错。
  • import 位置可灵活放置:仅为局部(如测试)使用的模块应放在相应代码块内导入,避免给使用者带来链式加载的性能开销。

关联内容

  • 前置知识:函数定义与调用(第 3 章)、文件的读写与路径概念、程序输入输出(input)。
  • 与 C 语言头文件机制类比(呼应课程概述中对多语言的介绍)。
  • 下接 9.2 模块进阶:sys.path 搜索路径、模块编译与 __pycache__;9.3 包:多个模块组成的文件夹结构。
  • 第三方库的安装与使用(第 10 章"第三方库与虚拟环境")与本章紧密衔接,老师提到 pip install 安装的库会出现在 sys.path 的 site-packages 中。