1+1=10

记记笔记,放松一下...

Python Import机制乱谈(二)

接前面Python Import机制乱谈(一),继续看看

sys.path

导入模块时,需要从这里面的路径开始,那么它里面到底有什么东西

初始化值受什么影响?

这东西的生成逻辑太复杂了。

  • 脚本所在目录(如果执行的是脚本),或当前工作目录(如果使用 -m-c 参数。【所谓的不安全路径?】
  • 环境变量PYTHONPATH设置的路径
  • 与PYTHONHOME相关的 prefixexec_prefix
  • python<major><minor>.zip
  • site模块 与 site-packages

以及

  • pyvenv.cfg 文件
  • ._pth 文件

例子

把 sys.path 当作黑盒子,直接执行看看

执行 site 模块(1)

1
python -m site

输出内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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

1
python -P -m site

添加 -P 参数,(或者设置环境变量 PYTHONSAFEPATH 为非空值,比如1),结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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)

注意前面

1
USER_SITE: 'C:\\Users\\dbzha\\AppData\\Roaming\\Python\\Python312\\site-packages' (doesn't exist)

如果这个路径存在的话,输出结果会包含它

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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
python -m site

会怎么样?

 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下结果:

1
python -m site

如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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,可以用:

1
python -m site --user-site

其输出

在Ubuntu下:

1
/home/debao/.local/lib/python3.12/site-packages

在 Windows下:

1
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 相同

例子

如下命令结果?

1
python -c "import sys; print(sys.prefix, sys.exec_prefix)"

Windows:

1
C:\Python312 C:\Python312

Windows 下 venv

1
D:\Source\debao\debaoblog\.venv D:\Source\debao\debaoblog\.venv

Ubuntu:

1
/usr /usr

依据 sys.prefix != sys.base_prefix 可判定当前是否在venv环境中执行

pyvenv.cfg

在哪里?

使用 venv 创建虚拟环境,

在Windows下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
venv_name/
├── Scripts/                    # Windows下的可执行文件目录
   ├── python.exe            # Python解释器
   ├── pythonw.exe          # 无控制台的Python
   ├── pip.exe              
   ├── activate.bat         # cmd激活脚本
   └── Activate.ps1         # PowerShell激活脚本
├── Lib/
   └── site-packages/       # 第三方包目录
└── pyvenv.cfg               # 配置文件

在 Ubuntu下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
venv_name/
├── bin/               # Unix系统存放可执行文件
   ├── python        # Python解释器的软链接
   ├── pip          # pip的软链接
   └── activate     # 激活脚本
├── lib/
   └── pythonX.Y/
       └── site-packages/  # 第三方包安装位置
├── include/          # 头文件目录
└── pyvenv.cfg       # 配置文件

长什么样?

1
2
3
4
5
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,内容如下:

1
2
3
4
5
python312.zip
.

# Uncomment to run site.main() automatically
#import site

PIP 安装包位置?

pip 安装包的位置取决于以下情况:

venv环境中

  • venv/Lib/site-packages/

比如:'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/

用户级安装

1
pip install --user
  • Windows: %APPDATA%\Python\Python3x\site-packages\
  • Linux: ~/.local/lib/python3.x/site-packages/
  • macOS: ~/Library/Python/3.x/site-packages/

查看包位置

使用 <package>.__path__

1
python -c "import markdown as _; print(_.__path__)"

结果:

1
['D:\\Source\\debao\\debaoblog\\.venv\\Lib\\site-packages\\markdown']

使用 <package>.__file__

1
python -c "import markdown as _; print(_.__file__)"

结果:

1
D:\Source\debao\debaoblog\.venv\Lib\site-packages\markdown\__init__.py

或者直接 pip show:

1
pip show markdown

结果如下:

1
2
3
4
5
6
7
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:

安装后可执行:

1
path/to/conda init powershell

以便于:

  • 修改 PowerShell 的配置文件(通常在 $PROFILE 位置)
  • 添加必要的脚本来初始化 conda
  • 使 conda activate 和 conda deactivate 命令在 PowerShell 中可用

而后可以安装其他版本python:

1
2
conda create -n py311 python=3.11
conda create -n py310 python=3.10

注意和 conda install python=3.11 的不同,这是直接降级原来的 3.12。

而后

1
2
3
4
5
6
7
8
# 使用 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/

Python