[关闭]
@kpatrick 2022-07-05T20:32:17.000000Z 字数 5575 阅读 140

高质量 Python 代码编写和协作开发

Git 产险


1. Python 编码指南

代码格式,PEP指南:

2. 编码规范

2.1 Python 之禅

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

2.2 常见问题

2.2.1 命名约定

Python 库的命名约定有点混乱,不可能完全一致。但依然有些普遍推荐的命名规范的。新的模块和包 (包括第三方的框架) 应该遵循这些标准。对不同风格的已有的库,建议保持内部的一致性。

如今代码库中有多种命名风格:

有下划线的情况:

2.2.2 缩进

YES

  1. # 对准左括号
  2. foo = long_function_name(var_one, var_two,
  3. var_three, var_four)
  4. # 不对准左括号,但加多一层缩进,以和后面内容区别。
  5. def long_function_name(
  6. var_one, var_two, var_three,
  7. var_four):
  8. print(var_one)
  9. # 悬挂缩进必须加多一层缩进.
  10. foo = long_function_name(
  11. var_one, var_two,
  12. var_three, var_four)

NO

  1. # 不使用垂直对齐时,第一行不能有参数。
  2. foo = long_function_name(var_one, var_two,
  3. var_three, var_four)
  4. # 参数的缩进和后续内容缩进不能区别。
  5. def long_function_name(
  6. var_one, var_two, var_three,
  7. var_four):
  8. print(var_one)

2.2.3 空行

YES

  1. def add(a: int, b: int) -> int:
  2. return a + b
  3. def sub(a: int, b: int) -> int:
  4. return a - b
  1. class Calculator:
  2. def __init__(self):
  3. pass
  4. def add(self, a: int, b: int) -> int:
  5. return a + b
  6. def sub(self, a: int, b: int) -> int:
  7. return a - b

2.2.4 全局变量

变量尽量只用于模块内部,约定类似函数。

对设计为通过 from M import 来使用的模块,应采用 __all__ 机制来防止导入全局变量;或者为全局变量加一个前置下划线。

2.2.5 Docstring

2.2.6 TypeHint

......

3. 用辅助工具完成高质量代码编写

3.1 Git hooks

3.2 pre-commit

但是如果直接通过编写 git hooks 脚本来实现代码规范检查,会有如下的一些问题:

为了更方便的管理 pre-commit 的设置,于是有了一个同名的工具项目 pre-commit,一个用于管理和维护多语言预提交挂钩的框架。官网地址:https://pre-commit.com/

3.3 使用步骤

  1. 安装:pip install pre-commit
  2. 设置配置文件:pre-commit 依赖项目根目录配置文件 .pre-commit-config.yaml,需要手动在根目录创建此文件。
  3. 设置 git hooks 脚本:pre-commit install
  4. 对所有文件进行一次检查(可选):pre-commit run --all-files

3.4 个人配置推荐

根据个人开发经验,提交代码前完成对基础格式、文档、import 和 type hint 等方面进行检查,推荐的插件有以下 6 个:

通过此配置可以完成上述 6 个插件的安装(通过例子进行演示):.pre-commit-config.yaml

  1. - repo: https://github.com/pre-commit/pre-commit-hooks.git
  2. rev: v4.3.0
  3. hooks:
  4. - id: check-merge-conflict
  5. - id: check-symlinks
  6. - id: end-of-file-fixer
  7. - id: trailing-whitespace
  8. - repo: https://github.com/fsouza/autoflake8
  9. rev: v0.3.2
  10. hooks:
  11. - id: autoflake8
  12. - repo: https://github.com/psf/black
  13. rev: 22.6.0
  14. hooks:
  15. - id: black
  16. - repo: https://github.com/pycqa/pydocstyle
  17. rev: 6.1.1
  18. hooks:
  19. - id: pydocstyle
  20. args: [--convention, google, --add-ignore, D100]
  21. - repo: https://github.com/pre-commit/mirrors-mypy
  22. rev: v0.961
  23. hooks:
  24. - id: mypy
  25. args: [--disallow-untyped-defs, --ignore-missing-imports]
  26. - repo: https://github.com/pycqa/isort
  27. rev: 5.10.1
  28. hooks:
  29. - id: isort

4. 代码协作流程

jNNoGD.png

4.1 分支策略

当前基于 Git 的分支策略主要有 Gitflow、GitHub flow、GitLab flow 三个派别。如果无需执行严格的版本计划和保证定期发布相关需求的特性,一般可以采取最简便的GitHub flow。

GitHub flow 推荐的策略可以分成以下6步:

  1. Create a branch:在自己的本地仓库中,拉取最新的 Master 分支,并创建一个用于 开发新特性/修复问题 的 Feature 分支。
  2. Make changes:修改代码,并完成自测,pre-commit 检查和修复代码风格、格式和注释等问题。完成后将 Feature 提交至个人远程仓库。
  3. Create a pull request:提交一个 Pull Request/Merge Request,将个人远程仓库的 Feature 分支的 commits 请求合入 Master。
  4. Address review comments:管理员完成对 PR 的 Code Review,针对代码修改处的设计、规范、功能等进行逐一严格审查,审查不通过时要求开发者进行修改。此过程中还可能会有存在代码冲突、CI 等问题,可能会有多次循环。
  5. Merge your pull request:完成 Code Review 后,管理员将代码 Merge 进到 Master 分支。
  6. Delete your branch:可选步骤,开发者可以删除个人远程和本地的 Feature 分支。

4.2 Merge or Rebase

一般而言,当我们需要从一个分支获取信息,并且合并到当前分支时,我们可以采用 Rebase 或者 Merge 的操作。如图所示:你在一个 Feature 分支进行新特性的开发,与此同时,master 分支的也有新的提交。

jNUMQJ.png

4.2.1 Merge(推荐)

  1. git merge master feature

Merge 特点:

jNU8dx.png

4.2.2 Rebase(慎用)

  1. git checkout feature
  2. git rebase master

Rebase 特点:

Rebase 冲突:
合并时如果出现冲突需要按照如下步骤解决

jNUYFK.png

注意,不能在公共分支上执行 Rebase !Rebase 后不仅历史发生改变,所有开发者都受其影响。

jNUtJO.png

4.3 Code Reivew

从观念上,要把 Code Review 置于与代码开发和测试同等重要的地位。具体要做到以下几点:

  1. 对所有检查的代码逻辑要做到 完全看懂,对于审核的代码,熟悉程度要做到 如数家珍。如果在审核代码后,对代码的逻辑和背后的原因仍然很模糊,则是一个失败的 Code Review。
  2. 好代码的标准,不仅仅是 可以运行通过,在正确性、可读性、可重用性、可运维性等方面上,都需要综合考虑。
  3. 建立 Code Review 和写代码一样重要的意识。即:
    • Code Review 和写代码一样,也有产出,即产出更高质量的代码。
    • 审核代码在很多情况下比写代码还要辛苦,需要理解和找出问题等。
  4. 以提升代码质量为最终目标。
  5. 要投入足够的时间和精力:
    • 要有时间意识。审核代码花费的时间经常和写代码一样多,有时甚至比写代码的时间更多。
    • 要有责任意识。如果出现 Bug,不仅仅是写代码人员的职责,也不仅仅是 QA 的职责,代码审核者也需要承担相当大的责任。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注