接前面Python Import机制乱谈(一),继续看看
sys.path
导入模块时,需要从这里面的路径开始,那么它里面到底有什么东西
初始化值受什么影响?
这东西的生成逻辑太复杂了。
- 脚本所在目录(如果执行的是脚本),或当前工作目录(如果使用 
-m 或 -c 参数。【所谓的不安全路径?】 
- 环境变量PYTHONPATH设置的路径
 
- 与PYTHONHOME相关的 
prefix 和 exec_prefix  
python<major><minor>.zip 
- site模块 与 site-packages
 
以及
例子
把 sys.path 当作黑盒子,直接执行看看
执行 site 模块(1)
输出内容:
 | PS C:\Users\dbzha> C:\Users\dbzha>python -m site
sys.path = [
    'C:\\Users\\dbzha',
    'C:\\Python312\\python312.zip',
    'C:\\Python312\\DLLs',
    'C:\\Python312\\Lib',
    'C:\\Python312',
    'C:\\Python312\\Lib\\site-packages',
]
USER_BASE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (doesn't exist)
  | 
 
执行 site 模块(2) 使用 -P
添加 -P 参数,(或者设置环境变量  PYTHONSAFEPATH 为非空值,比如1),结果如下:
 | sys.path = [
    'C:\\Python312\\python312.zip',
    'C:\\Python312\\DLLs',
    'C:\\Python312\\Lib',
    'C:\\Python312',
    'C:\\Python312\\Lib\\site-packages',
]
USER_BASE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (doesn't exist)
ENABLE_USER_SITE: True
  | 
 
容易注意到:里面没有自动添加不安全的当前工作目录。
执行 site 模块(3)
注意前面
 | USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (doesn't exist)
  | 
 
如果这个路径存在的话,输出结果会包含它
 | sys.path = [
    'C:\\Python312\\python312.zip',
    'C:\\Python312\\DLLs',
    'C:\\Python312\\Lib',
    'C:\\Python312',
    'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages',
    'C:\\Python312\\Lib\\site-packages',
]
USER_BASE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (exists)
ENABLE_USER_SITE: True
  | 
 
执行 site 模块(4)venv环境
在 venv 环境下,执行
会怎么样?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12  | sys.path = [
    'D:\\Source\\debao\\debaoblog',
    'C:\\Python312\\python312.zip',
    'C:\\Python312\\DLLs',
    'C:\\Python312\\Lib',
    'C:\\Python312',
    'D:\\Source\\debao\\debaoblog\\.venv',
    'D:\\Source\\debao\\debaoblog\\.venv\\Lib\\site-packages',
]
USER_BASE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (exists)
ENABLE_USER_SITE: False
  | 
 
注意,USER SITE禁用状态
执行 site 模块(5)ubuntu
也可以对照Ubuntu下结果:
如下:
 | sys.path = [
    '/home/debao',
    '/usr/lib/python312.zip',
    '/usr/lib/python3.12',
    '/usr/lib/python3.12/lib-dynload',
    '/usr/local/lib/python3.12/dist-packages',
    '/usr/lib/python3/dist-packages',
]
USER_BASE: '/home/debao/.local' (doesn't exist)
USER_SITE: '/home/debao/.local/lib/python3.12/site-packages' (doesn't exist)
ENABLE_USER_SITE: True
  | 
 
执行 site 模块(6)use-site
如果只关注 user级别的 site,可以用:
 | python -m site --user-site
  | 
 
其输出
在Ubuntu下:
 | /home/debao/.local/lib/python3.12/site-packages
  | 
 
在 Windows下:
 | C:\Users\dbzha\AppData\Roaming\Python\Python312\site-packages
  | 
 
sys.prefix 与 sys.exec_prefix
是什么?
sys.prefix:
- 表示 Python 的安装路径根目录
 
- 包含与平台无关的 Python 文件,如标准库模块(.py文件)
 
- 默认情况下,在类Unix系统中通常是 "/usr" 或 "/usr/local"
 
- 在虚拟环境中,指向虚拟环境的根目录
 
sys.exec_prefix:
- 表示包含依赖平台的 Python 文件的根目录
 
- 包含编译后的扩展模块(.so文件)、可执行文件等
 
- 通常与 sys.prefix 相同
 
例子
如下命令结果?
 | python -c "import sys; print(sys.prefix, sys.exec_prefix)"
  | 
 
Windows:
 | C:\Python312 C:\Python312
  | 
 
Windows 下 venv
 | D:\Source\debao\debaoblog\.venv D:\Source\debao\debaoblog\.venv
  | 
 
Ubuntu:
依据 sys.prefix != sys.base_prefix 可判定当前是否在venv环境中执行
pyvenv.cfg
在哪里?
使用 venv 创建虚拟环境,
在Windows下
 | venv_name/
├── Scripts/                    # Windows下的可执行文件目录
│   ├── python.exe            # Python解释器
│   ├── pythonw.exe          # 无控制台的Python
│   ├── pip.exe              
│   ├── activate.bat         # cmd激活脚本
│   └── Activate.ps1         # PowerShell激活脚本
├── Lib/
│   └── site-packages/       # 第三方包目录
└── pyvenv.cfg               # 配置文件
  | 
 
在 Ubuntu下:
 | venv_name/
├── bin/               # Unix系统,存放可执行文件
│   ├── python        # Python解释器的软链接
│   ├── pip          # pip的软链接
│   └── activate     # 激活脚本
├── lib/
│   └── pythonX.Y/
│       └── site-packages/  # 第三方包安装位置
├── include/          # 头文件目录
└── pyvenv.cfg       # 配置文件
  | 
 
长什么样?
 | home = C:\Python312
include-system-site-packages = false
version = 3.12.1
executable = C:\Python312\python.exe
command = C:\Python312\python.exe -m venv D:\Source\debao\debaoblog\.venv
  | 
 
- 标记这是个虚拟环境,并指向原始Python解释器位置(home字段)
 
- 控制是否可以使用系统安装的包(include-system-site-packages)
 
- 影响Python的模块搜索路径(通过调整sys.prefix和sys.base_prefix)
 
- 记录Python版本和环境创建信息(version和executable字段)
 
- 为虚拟环境的隔离机制提供必要的配置信息
 
._pth 与 .pth
注意区分二者
| 特性 | 
._pth | 
.pth | 
| 文件名 | 
必须是 python版本号._pth | 
任意名称,以 .pth 结尾 | 
| 位置 | 
python.exe 同目录 | 
site-packages 目录 | 
| 路径控制 | 
完全替换 sys.path | 
追加到 sys.path | 
| 默认路径 | 
禁用所有默认路径 | 
保留默认路径 | 
| PYTHONPATH | 
禁用 | 
保留有效 | 
| 主要用途 | 
嵌入式/便携版 Python | 
添加额外包路径 | 
| 使用场景 | 
需要严格控制导入 | 
普通包管理 | 
Python的嵌入式版本,会提供一个 ._pth文件,比如 python312._pth,内容如下:
 | python312.zip
.
# Uncomment to run site.main() automatically
#import site
  | 
 
PIP 安装包位置?
pip 安装包的位置取决于以下情况:
venv环境中
比如:'D:\Source\debao\debaoblog\.venv\Lib\site-packages'
全局环境中
- Windows: C:\Python3x\Lib\site-packages\
 
- Linux: /usr/lib/python3.x/site-packages/
 
- macOS: /Library/Python/3.x/site-packages/
 
用户级安装
- Windows: %APPDATA%\Python\Python3x\site-packages\
 
- Linux: ~/.local/lib/python3.x/site-packages/
 
- macOS: ~/Library/Python/3.x/site-packages/
 
查看包位置
使用 <package>.__path__:
 | python -c "import markdown as _; print(_.__path__)"
  | 
 
结果:
 | ['D:\\Source\\debao\\debaoblog\\.venv\\Lib\\site-packages\\markdown']
  | 
 
使用 <package>.__file__:
 | python -c "import markdown as _; print(_.__file__)"
  | 
 
结果:
 | D:\Source\debao\debaoblog\.venv\Lib\site-packages\markdown\__init__.py
  | 
 
或者直接 pip show:
结果如下:
 | Name: Markdown
Version: 3.7
Summary: Python implementation of John Gruber's Markdown.
...
Location: D:\Source\debao\debaoblog\.venv\Lib\site-packages
Requires:
Required-by: markdown-mermaidjs, mdx-truly-sane-lists, pelican-yaml-metadata
  | 
 
便携式Python?
默认Python需要安装,为了便携,不少人在搞,比如:
- https://winpython.github.io/
 
- https://github.com/codrsquad/portable-python
 
另外还有 anaconda(miniconda)
conda
似乎不直接相关,它可以管理不同版本的python。先放上
比如Windows下,当前 Miniconda3-latest-Windows-x86_64.exe 对应的是 Python3.12:
安装后可执行:
 | path/to/conda init powershell
  | 
 
以便于:
- 修改 PowerShell 的配置文件(通常在 $PROFILE 位置)
 
- 添加必要的脚本来初始化 conda
 
- 使 conda activate 和 conda deactivate 命令在 PowerShell 中可用
 
而后可以安装其他版本python:
 | conda create -n py311 python=3.11
conda create -n py310 python=3.10
  | 
 
注意和 conda install python=3.11 的不同,这是直接降级原来的 3.12。
而后
 | # 使用 Python 3.11
conda activate py311
# 使用 Python 3.10
conda activate py310
# 回到基础环境,等同 conda activate
conda activate base
  | 
 
参考
- https://docs.python.org/3/library/sys_path_init.html
 
- https://github.com/python/cpython/blob/main/Modules/getpath.py
 
- https://docs.python.org/3/library/venv.html
 
- https://peps.python.org/pep-0370/
 
- https://pip.pypa.io/en/stable/cli/pip_install/
 
- https://docs.conda.io/en/latest/