引言
想象一下:你正在开发一个Python项目,每次运行测试都需要输入python3 -m pytest tests/ --verbose --cov=src
。格式化代码时要运行black . && isort .
。进行代码检查时又要执行flake8 src tests
。很快你就会发现自己需要记住十几个不同的命令,而你的团队成员也在用略有不同的方式执行相同的操作。
这时Makefile就能派上用场。虽然最初用于C和C++项目,但Makefile在Python开发中同样非常有用,可以作为一种简单的方法来标准化和自动化常见任务。你可以把Makefile看作是一个集中定义所有重复操作快捷方式的地方。
为什么在Python项目中使用Makefile?
团队协作的一致性
当团队中的每个人都使用make test
而不是记住带有所有参数的确切pytest命令时,你就能消除"在我机器上能运行"的问题。新团队成员可以快速上手,立即知道如何运行测试、格式化代码或部署应用。
真正有效的文档
简化复杂工作流
某些任务需要多个步骤。你可能需要安装依赖、运行迁移、填充测试数据,然后启动开发服务器。使用Makefile后,这只需要一个make dev
命令就能完成。
创建第一个Python Makefile
让我们逐步构建一个实用的Makefile。在项目根目录创建一个名为Makefile(无扩展名)的文件。
基本结构和帮助命令
这段代码为Makefile创建了一个自动帮助系统,显示所有可用命令及其描述:
|
|
.PHONY: help
告诉Make"help"不是一个真实文件,而是一个要运行的命令。当你输入make help
时,它会先打印"可用命令:",然后使用grep和awk的组合扫描Makefile本身,找到所有包含命令名称后跟##描述的行,并将它们格式化为带有命令名称和解释的可读列表。
环境设置
这段代码创建了三个环境管理命令:
|
|
install命令运行pip两次,从requirements文件安装主要依赖和开发工具。venv命令创建一个名为"venv"的Python虚拟环境文件夹,并打印激活说明。
clean命令删除Python在开发过程中创建的所有杂乱文件。它会删除编译的Python文件(.pyc)、缓存文件夹(pycache)、包信息目录以及构建产物如覆盖率报告和测试缓存。
代码质量和测试
这段代码创建了代码质量命令:
|
|
format命令使用black进行格式化和isort进行导入组织,自动修复代码样式。
lint命令在不更改任何内容的情况下检查代码是否遵循样式规则。flake8查找样式违规,而black和isort以仅检查模式运行,查看是否需要格式化。
test命令运行测试套件。test-cov运行测试并测量代码覆盖率,生成报告。check命令通过依赖lint和test命令,同时运行代码检查和测试。
开发工作流
这段代码创建了开发工作流命令:
|
|
dev命令首先运行install命令设置依赖,然后打印成功消息和后续步骤。serve命令以调试模式启动Flask开发服务器。
shell命令启动一个已经连接到Flask应用上下文的IPython shell,这样你就可以交互式地测试数据库查询和应用功能,而无需手动导入所有内容。
更多Makefile技巧
使用变量
你可以定义变量来避免重复:
|
|
条件命令
有时你需要根据环境有不同的行为:
|
|
文件依赖
你可以让目标依赖于文件,这样它们只在需要时运行:
|
|
🔗 这是一个完整的Flask Web应用Makefile示例。
最佳实践和技巧
以下是编写Makefile时应遵循的一些最佳实践:
- 不要过度复杂化你的Makefile。如果任务变得复杂,考虑将逻辑移到单独的脚本中,并从Make调用它。
- 选择能清楚表明其功能的命令名称。
make test
比make t
更好,make dev-setup
比make setup
更清晰。 - 对于不创建文件的命令,始终将它们声明为
.PHONY
。这可以防止有人创建与你的命令同名的文件时出现问题。 - 组织你的Makefile,将相关功能分组在一起。
- 确保所有命令都能在全新克隆的仓库中工作。没有什么比一个损坏的设置过程更让新贡献者沮丧了。
结论
Makefile可能看起来像是一个老式工具,但它们在Python项目中非常有效。它们为常见任务提供一致的接口,并帮助新贡献者快速上手。
首先创建一个只包含install、test和help命令的基本Makefile。随着项目的增长和工作流变得更加复杂,你可以根据需要添加更多目标和依赖。
记住,目标不是创建最聪明或最复杂的Makefile,而是让你的日常开发任务更容易、更可靠。保持简单,保持实用,让你的Makefile成为命令中心,为Python项目的混乱带来秩序。