当你编写一个独立的Python脚本时,目录结构看起来可能没什么特别。但随着项目逐渐变得复杂,你可能会倾向于将一些功能分离到其他模块或包中。这时,你可能会发现在源文件旁边,似乎毫无规律地,突然冒出一个__pycache_
_文件夹。
project/
│
├── mathematics/
│ │
│ ├── __pycache__/
│ │
│ ├── arithmetic/
│ │ ├── __init__.py
│ │ ├── add.py
│ │ └── sub.py
│ │
│ ├── geometry/
│ │ │
│ │ ├── __pycache__/
│ │ │
│ │ ├── __init__.py
│ │ └── shapes.py
│ │
│ └── __init__.py
│
└── calculator.py
请留意,当您的项目目录结构中有多级嵌套的子包时,pycache 文件夹可能会随机出现在不同的层级。与此同时,存放您 Python 源代码的其他包或文件夹,可能并没有这个神秘的缓存文件夹。
在您克隆了包含Python项目的远程Git仓库并执行了相应的代码之后,您可能会碰到相似的问题。究竟是什么触发了 pycache 文件夹的生成,它又有什么作用呢?
简而言之:它使导入 Python 模块更快
虽然 Python 属于解释型语言,但其解释器并不是直接执行您的 Python 代码,这样做效率会很低。实际上,当您执行一个 Python 脚本或导入模块时,解释器会先将您的源代码转换成字节码,这是一种代码的中间二进制形式。
这种字节码允许解释器省略掉一些重复的操作,比如每次执行程序时都重新进行词法分析、解析成抽象语法树以及验证代码的正确性。只要源代码保持不变,Python 就可以直接使用这个已经准备好的中间表示来执行,从而节省了时间,加快了脚本的启动速度。
要记住的是,通过 pycache 加载编译后的字节码确实可以加快 Python 模块的导入速度,但这并不会影响到模块的执行速度。
Python 利用项目中的 pycache 文件夹来存放已编译的模块字节码。当您再次运行程序时,如果这些字节码与源文件保持同步更新,解释器会尝试从这些文件夹中加载模块的预编译版本。需要指出的是,这种缓存机制仅在您通过代码导入模块时激活,而不是在命令行中直接执行脚本。
除了磁盘上的字节码缓存,Python 还维护了一个内存中的模块缓存,您可以通过 sys.modules 字典来访问。这确保了在您的程序中多次从不同位置导入同一个模块时,Python 会直接使用已导入的模块,无需再次加载或编译。这两种机制相辅相成,有效降低了导入 Python 模块所需的开销。