Skip to content

Python 项目结构 ​

良好的项目结构让代码易于维护、测试和分发。Python 社区有成熟的最佳实践。

标准项目结构 ​

推荐布局(src layout):

my_project/
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   ├── test_core.py
│   └── test_utils.py
├── docs/
│   └── index.md
├── pyproject.toml
├── README.md
├── LICENSE
└── .gitignore

关键组件:

  • src/:源代码目录(推荐)
  • tests/:测试代码
  • docs/:文档
  • pyproject.toml:项目配置
  • README.md:项目说明
  • LICENSE:许可证

src layout vs flat layout ​

src layout(推荐) ​

my_project/
├── src/
│   └── my_package/
│       └── __init__.py
└── tests/

优点:

  • 强制安装后测试(避免导入本地未安装版本)
  • 清晰的命名空间
  • 避免测试导入冲突

flat layout ​

my_project/
├── my_package/
│   └── __init__.py
└── tests/

缺点:

  • 可能导入本地代码而非安装版本
  • 测试可能通过但安装后失败

init.py 的作用 ​

标记目录为 Python 包:

python
# src/my_package/__init__.py
"""My Package - 一个示例包"""

__version__ = "0.1.0"

from .core import main_function
from .utils import helper_function

__all__ = ["main_function", "helper_function"]

Python 3.3+:空目录也可以是包(namespace package),但显式 __init__.py 更清晰。

虚拟环境 ​

隔离项目依赖,避免冲突。

venv(标准库) ​

bash
# 创建虚拟环境
python3 -m venv venv

# 激活(Linux/macOS)
source venv/bin/activate

# 激活(Windows)
venv\Scripts\activate

# 安装依赖
pip install requests pytest

# 退出
deactivate

virtualenv(第三方) ​

bash
pip install virtualenv
virtualenv venv
source venv/bin/activate

选择:venv 是标准库,优先使用。

依赖管理 ​

requirements.txt(传统) ​

txt
requests==2.31.0
pytest>=7.0.0
black~=23.0
bash
pip install -r requirements.txt
pip freeze > requirements.txt

pyproject.toml(现代,推荐) ​

toml
[project]
name = "my-package"
version = "0.1.0"
description = "A sample package"
requires-python = ">=3.10"
dependencies = [
    "requests>=2.31.0",
    "click>=8.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "black>=23.0",
    "mypy>=1.0",
]

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

安装:

bash
# 安装包
pip install -e .

# 安装开发依赖
pip install -e ".[dev]"

pyproject.toml vs setup.py ​

特性pyproject.tomlsetup.py
标准PEP 621(现代)传统
格式声明式(TOML)命令式(Python)
推荐✅ 新项目遗留项目

迁移:

python
# setup.py(旧)
from setuptools import setup

setup(
    name="my-package",
    version="0.1.0",
    install_requires=["requests"],
)
toml
# pyproject.toml(新)
[project]
name = "my-package"
version = "0.1.0"
dependencies = ["requests"]

项目模板 ​

cookiecutter ​

bash
pip install cookiecutter

# 使用模板
cookiecutter https://github.com/audreyr/cookiecutter-pypackage

# 回答提示创建项目

手动创建 ​

bash
mkdir my_project
cd my_project
mkdir -p src/my_package tests docs
touch src/my_package/__init__.py
touch tests/__init__.py
touch pyproject.toml README.md LICENSE

实战案例:创建完整项目 ​

bash
# 1. 创建结构
mkdir calculator_project
cd calculator_project
mkdir -p src/calculator tests

# 2. 源代码
cat > src/calculator/__init__.py << 'EOF'
"""Simple calculator package"""
__version__ = "0.1.0"

from .operations import add, subtract, multiply, divide

__all__ = ["add", "subtract", "multiply", "divide"]
EOF

cat > src/calculator/operations.py << 'EOF'
def add(a: float, b: float) -> float:
    return a + b

def subtract(a: float, b: float) -> float:
    return a - b

def multiply(a: float, b: float) -> float:
    return a * b

def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b
EOF

# 3. 测试
cat > tests/test_operations.py << 'EOF'
from calculator.operations import add, divide
import pytest

def test_add():
    assert add(2, 3) == 5

def test_divide_by_zero():
    with pytest.raises(ValueError):
        divide(10, 0)
EOF

# 4. 配置
cat > pyproject.toml << 'EOF'
[project]
name = "calculator"
version = "0.1.0"
requires-python = ">=3.10"

[project.optional-dependencies]
dev = ["pytest>=7.0"]
EOF

# 5. 安装和测试
python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
pytest

小结 ​

  • src layout 是推荐的项目结构
  • pyproject.toml 替代 setup.py(PEP 621)
  • 虚拟环境 隔离项目依赖
  • init.py 标记包并定义公共 API
  • 项目模板 加速新项目创建

下一节学习 测试基础。


参考:PEP 621 – Python Project Metadata

练习:答案

用心记录每一步成长