PyScaffold 新手使用手册
—— Python 工程化开发入门指南
1. PyScaffold 是什么?
PyScaffold 是一个 Python 项目脚手架工具,它能帮你:
✅ 自动生成标准化的项目结构(符合 Python 最佳实践)
✅ 集成常用工具(测试、文档、打包等)
✅ 减少手动配置,让你专注于代码开发
适合人群:
- 刚接触 Python 工程化的新手
- 想规范化项目结构的开发者
- 需要快速搭建 Python 库或工具的人
2. 安装 PyScaffold
在终端(Windows 用 CMD/PowerShell,Mac/Linux 用 Terminal)运行:
pip install pyscaffold
⚠️ 建议使用 Python 3.7+,并确保
pip已更新(pip install --upgrade pip)。
3. 快速创建项目
基础命令
putup my_project # 创建一个名为 my_project 的 Python 项目
这会生成以下目录结构:
my_project/
├── src/
│ └── my_project/ # 你的代码放在这里
│ └── init.py
├── tests/ # 测试代码
├── docs/ # 文档
├── setup.cfg # 项目配置(依赖、作者信息等)
├── pyproject.toml # 构建配置
└── README.md # 项目说明
常用选项
| 选项 | 作用 | 示例 |
|---|---|---|
--package |
指定包名(默认同项目名) | putup my_project --package mypkg |
--pre-commit |
启用 Git 提交前检查 | putup my_project --pre-commit |
--black |
启用代码自动格式化 | putup my_project --black |
--license |
添加开源协议(如 MIT) | putup my_project --license MIT |
完整命令示例:
putup my_project --pre-commit --black --license MIT
4. 项目结构详解
| 文件/目录 | 作用 |
|---|---|
src/my_project/ |
项目主代码(__init__.py 是包入口) |
tests/ |
单元测试(PyScaffold 默认用 pytest) |
docs/ |
文档(默认支持 sphinx) |
setup.cfg |
项目元数据(名称、版本、依赖等) |
pyproject.toml |
构建系统配置(兼容 pip 和 build) |
5. 开发流程
(1) 安装开发依赖
进入项目目录后运行:
pip install -e .[testing,docs] # -e 表示“可编辑模式”,修改代码无需重装
(2) 编写代码
-
将你的 Python 模块放在
src/my_project/下。 -
示例:创建
src/my_project/calculator.py:def add(a, b):
return a + b
(3) 运行测试
PyScaffold 默认集成 pytest,直接运行:
pytest
测试文件示例(tests/test_calculator.py):
from my_project.calculator import add
def test_add():
assert add(1, 2) == 3
(4) 生成文档
cd docs && make html # 生成 HTML 文档,输出在 docs/_build/html/
(5) 打包发布
python -m build # 生成 dist/ 下的安装包
pip install dist/my_project-0.1.tar.gz # 本地测试安装
6. 进阶功能
(1) 启用 Git 版本控制
git init
git add .
git commit -m "Initial commit"
如果用了 --pre-commit,提交时会自动检查代码格式。
(2) 添加更多依赖
在 setup.cfg 的 install_requires 中添加:
install_requires =
numpy>=1.20
pandas
(3) 扩展 PyScaffold
通过插件支持 Django、Flask 等框架:
pip install pyscaffoldext-django # Django 项目模板
putup my_django_project --django
7. 常见问题
❌ 问题1:putup 命令找不到?
👉 确保 PyScaffold 已安装,或尝试 python -m pyscaffold.cli putup my_project。
❌ 问题2:运行 pytest 报错?
👉 检查是否安装了开发依赖(pip install -e .[testing])。
❌ 问题3:如何更新项目配置?
👉 直接修改 setup.cfg 或重新生成项目(需备份代码)。
8. 总结
- PyScaffold 帮你自动化:项目初始化、测试配置、文档生成。
- 适合场景:开发 Python 库、工具或团队协作项目。
- 下一步学习:
🎉 现在你可以用 PyScaffold 快速启动一个专业的 Python 项目了!
Python 面向对象编程 (OOP) 代码模板
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
module_name.py
A description of what this module/class does.
"""
from typing import Optional, Any, List, Dict # 类型注解支持
class BaseClass:
"""Base class documentation string.
This is a base class that demonstrates proper Python OOP structure.
"""
# 类常量 (全大写命名)
CLASS_CONSTANT = "default_value"
def __init__(self, param1: str, param2: int = 42) -> None:
"""Initialize the BaseClass.
Args:
param1: Description of param1
param2: Description of param2 (default: 42)
"""
self.public_attr = param1 # 公共属性
self._protected_attr = param2 # 受保护属性 (单下划线前缀)
self.__private_attr = "private" # 私有属性 (双下划线前缀)
def public_method(self) -> str:
"""Public method that does something.
Returns:
str: Description of return value
"""
return f"Public: {self.public_attr}"
def _protected_method(self) -> int:
"""Protected method (should only be used internally or by subclasses)."""
return self._protected_attr * 2
def __private_method(self) -> str:
"""Private method (name mangled, not accessible directly from outside)."""
return f"Private: {self.__private_attr}"
@property
def calculated_property(self) -> float:
"""Example property that computes a value.
Returns:
float: The computed value
"""
return self._protected_attr / 2
@calculated_property.setter
def calculated_property(self, value: float) -> None:
"""Property setter with validation."""
if value <= 0:
raise ValueError("Value must be positive")
self._protected_attr = int(value * 2)
@classmethod
def from_alternative_constructor(cls, param: str) -> 'BaseClass':
"""Alternative constructor as a class method.
Args:
param: Description of parameter
Returns:
BaseClass: New instance of the class
"""
return cls(param1=param, param2=len(param))
@staticmethod
def utility_function(text: str) -> str:
"""Static method that doesn't require instance access.
Args:
text: Input string
Returns:
str: Processed string
"""
return text.upper()
def __str__(self) -> str:
"""String representation of the object."""
return f"BaseClass({self.public_attr})"
def __repr__(self) -> str:
"""Unambiguous representation for debugging."""
return f"BaseClass(param1={repr(self.public_attr)}, param2={self._protected_attr})"
class ChildClass(BaseClass):
"""Child class demonstrating inheritance."""
def __init__(self, param1: str, param3: list, param2: int = 100) -> None:
"""Initialize the child class.
Args:
param3: New parameter specific to child class
"""
super().__init__(param1, param2) # 调用父类初始化
self.param3 = param3
def public_method(self) -> str: # 方法重写
"""Override parent method with extended functionality."""
parent_result = super().public_method()
return f"Child: {parent_result} + {self.param3}"
def child_specific_method(self) -> List[str]:
"""Method only available in child class."""
return [str(item) for item in self.param3]
# 抽象基类示例
from abc import ABC, abstractmethod
class AbstractShape(ABC):
"""Abstract base class defining an interface for shapes."""
@abstractmethod
def area(self) -> float:
"""Calculate the area of the shape."""
pass
@abstractmethod
def perimeter(self) -> float:
"""Calculate the perimeter of the shape."""
pass
class Circle(AbstractShape):
"""Concrete implementation of AbstractShape for circles."""
def __init__(self, radius: float) -> None:
self.radius = radius
def area(self) -> float:
return 3.14159 * self.radius ** 2
def perimeter(self) -> float:
return 2 * 3.14159 * self.radius
# 混入类 (Mixin) 示例
class JSONMixin:
"""Mixin class adding JSON serialization capability."""
def to_json(self) -> str:
"""Convert object to JSON string."""
import json
return json.dumps(self.__dict__)
class EnhancedClass(BaseClass, JSONMixin):
"""Class demonstrating multiple inheritance with a mixin."""
pass
if __name__ == "__main__":
# 示例用法
base = BaseClass("test")
print(base.public_method())
child = ChildClass("child", [1, 2, 3])
print(child.public_method())
circle = Circle(5)
print(f"Area: {circle.area():.2f}")
enhanced = EnhancedClass("json")
print(enhanced.to_json())
my_project/
├── src/
│ └── my_package/
│ ├── __init__.py # 包初始化文件
│ ├── base_module.py # 基础类定义
│ ├── subpackage/
│ │ ├── __init__.py
│ │ └── specialized.py # 特定功能类
│ └── utils.py # 工具函数/类
├── tests/
│ ├── __init__.py
│ ├── test_base.py # 单元测试
│ └── test_integration.py # 集成测试
├── docs/ # 文档
├── setup.py # 包配置
└── README.md # 项目说明
浙公网安备 33010602011771号