python包管理

在archlinux上,安装python包有两种方式:

  1. 通过系统包管理器安装,比如sudo pacman -S python-pandas
  2. 创建虚拟环境,在某个项目路径下使用pip安装到虚拟环境。也可通过uv等现代工具管理。 为了避免依赖冲突,我推荐在积累自己的代码时只用第2种方式。第1种方式只用于系统在安装软件时安装某些python依赖项,而不用于手动安装项目依赖的python包.
  • 创建和使用虚拟环境的传统方法(推荐使用uv或poetry而不是这么做)
python -m venv .venv            # 创建虚拟环境.venv
source .venv/bin/activate       # 启用虚拟环境.venv
pip install pandas              # 安装包到虚拟环境目录下(.venv/lib/pythonx.xx/site-packages)
pip freeze > requirements.txt   # 导出当前虚拟环境下安装的包(主动安装的包和它们的依赖混在一起)
pip install -r requirements.txt # 通过包列表安装py包
  • 代替requirements.txt – 现代python包管理的统一标准:pyproject.toml
[project]
name = "proj"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
    "pandas==2.3.1"
]

有了这个文件后下面的命令,会对当前项目进行打包,然后和依赖项一起安装到虚拟环境下

pip install -e . #使用-e是为了不将自己的源代码复制到虚拟环境,而只是创建链接,保证所有修改立即生效。
  • 以上流程又需要手动查包的版本号,所以产生了更加方便的工具,比如uv,它能把以上创建虚拟环境和编辑pyproject.toml的流程自动化(只需要有个最初的包含项目版本号的pyproject.toml文件)
uv add pandas  # 把某个包添加到虚拟环境(不需要手动启动虚拟环境)
uv sync        # 根据当前pyproject.toml文件搭建项目的虚拟环境
uv run main.py # 在当前路径虚拟环境的上下文中执行命令

python项目结构与打包

一般在用与包名相同的目录存放所有代码(flat layout)后,再把它放进src/下(src layout)。

.
|_ doc/
|_ scratch/
|_ src/
    |_ myproject/
        |_ __init__.py  # 项目的代码目录中,这个文件作为可导入包的标记
|_ test/

项目构建用工具

  • frontend: build(官方工具,需要先安装)/ uv
  • backend: setuptools (官方,历史包袱太重)/ hatchling 使用这hatchling需要在pyproject.toml中指定:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/myproject"]

这里"myproject"是项目中存放代码的路径名 构建的命令是

python -m build # 使用build
uv build        # 使用uv

注意,如果使用build而不是uv,在开发阶段要执行一次以下命令,将项目本身链接到虚拟环境,这样能保证模块之间能通过相对路径import

pip install -e .

个人python函数的积累策略

个人函数库

只用一个库积累可复用性高的函数,分不同子包存放不同领域的python脚本。这个包需要发布到pypi上,方便在其他项目中使用。

~/workspace/lib/python/shadowslib/
├── .venv/
├── pyproject.toml
└── src/shadowslib/
    ├── __init__.py
    └── data/               # 数据处理与画图
        ├── __init__.py
        ├── moudle1.py
        ├── moudle2.py
        └── _archive/
    └── ui/                 # 人机交互
        ├── __init__.py
        ├── moudle1.py
        ├── moudle2.py
        └── _archive/
    └── ...                 # 其他分类

注:_archive/路径用来存放写好后几乎没被用到过但又舍不得删的函数。

  • __init__.py文件中,用__all__这个列表变量选择要对外暴露的函数
  • _archive/路径下没有__init__.py文件,因此它不会被当成一个子包。

在其它项目中使用个人函数库

如果只是单独使用一个脚本,尽量不要引入shadowslib中不包含的依赖包。

  1. 对于一个没有引入额外依赖的且不会发布的python脚本

    • 因为我们在.bashrc中,我们直接使用shadowslib的虚拟环境的路径作为PYTHONPATH,这样就可以在脚本中直接导入shadowslib
    export PYTHONPATH=/home/shadows/workspace/lib/python/shadowslib/.venv/lib/python3.13/site-packages:$PYTHONPATH
    
    • 所以可以在脚本中直接导入shadowslib,不需要包管理
    from shadowslib.data import moudle1
    from shadowslib.ui import moudle2
    
  2. 对于一个可能会发布的或会使用额外依赖的项目,要创建它自己的虚拟环境,并在其中使用shadowslib作为依赖。

    • 在项目目录下创建一个pyproject.toml文件,内容如下:
    [project]
    name = "myproject"
    version = "0.1.0"
    requires-python = ">=3.13"
    dependencies = [
        # 由于已经在.bashrc中设置了PYTHONPATH,所以可以直接导入shadowslib,而不用本地路径
        # 其它人使用这个项目时,包管理工具会从pypi上下载shadowslib
        "shadowslib>=0.1.0"
        ]
    
    • 然后在项目目录下执行以下命令安装依赖(也可以直接使用uv run命令来运行脚本)
    uv sync