9.2 模块与包——模块进阶¶
内容梗概¶
本课讲解模块的两个进阶话题。第一是模块的搜索路径:导入模块时 Python 先查内置模块,再按 sys.path 列表的顺序逐个目录查找 .py 文件;sys.path 由当前脚本目录、PYTHONPATH 环境变量和 Python 安装目录三部分组成。由此引出"文件名不要与标准库同名"的重要教训,并用自建的假 turtle.py 覆盖真库的演示加以说明,同时区分了真正内置的模块(如 sys、os)不可被覆盖这一例外。第二是模块的编译缓存机制:导入模块时 Python 会把 .py 编译成字节码 .pyc 存入 __pycache__ 目录,源码未变时下次直接加载以提升效率,老师还顺带提到 .pyc 逆向在 CTF 比赛中的应用。
知识点详解¶
模块的搜索路径(约 00:00–05:45)¶
- 问题:运行
python cuc.py时,其中import calc,Python 按什么逻辑找到对应的.py文件? - 搜索规则:
- 先找**内置模块**——如
sys这样内嵌在 Python 解释器里的特殊模块,不走sys.path搜索,数量很少。 - 其余模块去
sys.path(一个列表)对应的各个路径中,**按顺序、按优先级**挨个查找,找到即导入,找不到就继续下一个目录。 - 类比:与操作系统的环境变量(Windows 查找 exe 的 PATH)是同样的思路。
sys.path的三部分构成(约 03:08):- 当前目录:即被运行脚本(如
cuc.py)所在的目录,排在最前。 PYTHONPATH环境变量:若操作系统中定义了该变量,其中的路径会被加入列表(老师机器上未定义)。- Python 安装目录下的相关路径,包括:zip 包(可直接搜索 zip 内模块)、
DLLs目录、lib目录(放默认自带的库,如os)、安装根目录、用户目录下的 Python 目录,以及lib/site-packages——用pip install安装的第三方库都放在这里。
同名文件覆盖标准库的问题(约 05:45–13:48)¶
- 由于
sys.path中当前目录优先级最高,若在自己的脚本目录下新建了与库同名的.py文件,会**覆盖**后面路径中的真正库。 - 演示:课程最开始用过
turtle库画小乌龟的例子。在当前目录建一个turtle.py,里面只写一句print("wrong turtle");再运行画图程序时,导入的是这个假 turtle,调用turtle.Screen()初始化画布时报错(假模块里没有Screen),真正的 turtle 库被覆盖。 - 重要结论(老师反复强调):创建文件时不要起与 Python 自带库同名的文件名,避免冲突;不确定有哪些自带库就去查文档。文件名写得完整、稍长一点更稳妥。
- 例外情况(约 09:49):即使建了
sys.py,import sys仍然导入真正的 sys 模块。原因是 Python 自带的模块分几层: - 真正的内置模块(
sys、os等,内嵌解释器)——搜索优先级最高,无法被同名文件覆盖; - 安装时自带但非内置的模块(如
turtle)——会被覆盖; - 用
pip安装的第三方模块——也会被覆盖。 - 偷懒记法:反正尽量不起同名名字就对了。
- 排错思路(约 13:25):如果某个明明已安装/自带的库不能正常工作,要想到搜索优先级问题——**检查当前目录下有没有同名文件**导致导入了错误的库。
模块的编译与 __pycache__(约 13:49–17:44)¶
- 回顾:Python 是解释型语言,但解释器执行前会先把源码 compile(编译)成字节码,再由 PVM(Python Virtual Machine,Python 虚拟机)运行字节码。
- 字节码即编译后得到的
.pyc文件,执行和加载速度更快、效率更高。 - 在
cuc.py中导入模块后,目录下会自动生成__pycache__(双下划线包裹,Python 保留命名)目录,里面是刚导入的模块编译出的.pyc文件。 - 命名规则:
模块名.cpython-37.pyc——模块名 + 解释器标识(CPython,即 C 语言实现的解释器)+ 版本号(如 3.7、3.8)。 - 机制:第一次加载时编译并缓存;第二次加载时若发现源码未更新,直接加载字节码,提高运行效率(Python 运行效率常被诟病,此机制是一种弥补)。
- 拓展(约 17:11):对打 CTF 比赛的同学,
.pyc是一个突破口——对方可能只给编译好的字节码而不给源码,可以分析字节码**逆向**推出模块功能。
示例与演示¶
- 打印
sys.path:展示列表中的多个路径,逐一对照讲解其来源(当前目录 → 环境变量 → 安装目录各子目录 →site-packages),并现场打开 Python 安装目录查看DLLs、lib、site-packages等文件夹。 - 假
turtle.py覆盖演示:复制课程开头的小乌龟画图程序,在当前目录建同名turtle.py,运行后先打印假模块的语句,随后Screen调用报错;再演示建sys.py却不影响import sys,说明内置模块不可覆盖。 __pycache__演示:导入模块后查看自动生成的缓存目录及calc.cpython-37.pyc等文件,解释其命名与作用。
重点与难点¶
sys.path的搜索顺序:当前脚本目录优先级最高,这是同名文件覆盖标准库的根源。- 不要给文件起与标准库/第三方库同名的名字;遇到"库明明装了却不能用"的 bug,先查当前目录有无同名文件。
- 区分三类模块的可覆盖性:真正内置的(
sys、os)不可覆盖;自带非内置的(turtle)和 pip 第三方库会被当前目录同名文件覆盖。 .pyc字节码与__pycache__是自动产生的缓存,日常很少直接操作,但要知道该机制的存在。
关联内容¶
- 上接 9.1 模块基础:模块的导入方式、
sys模块(本课的sys.path即其属性之一)。 - 呼应课程早期内容:
turtle小乌龟画图示例(第 1 章课程概述中的实例);Python 解释执行与编译为字节码的原理(Python 语言介绍部分);相对路径与环境变量的概念。 - 下接 9.3 包:模块组织为文件夹形成包;第 10 章将讲
pip install安装第三方库(对应本课的site-packages)与虚拟环境管理。 - 拓展方向:CTF 中的
.pyc逆向分析。