2020 年,PEP8 指定一行最大长度 79 的标准是否值得坚持?

PEP8 是 Python 官方编码风格指南,是每个 Python 工程师都要遵守的规范。我认为养成良好的编码习惯是非常重要的,因为代码是写给人读的,一手漂亮的代码看起来就是赏心悦目。我从学习 Python 开始没多久就开始刻意的遵守 PEP8,对其中绝大部分的规范都没有异议,以我的工程经验,PEP8 基本覆盖了日常开发涉及到的各个地方。

这篇文章主要讨论「Maximum Line Length」部分规定的「最大行长度为 79 个字符」这项。首先明确一点,这个 79 的长度一直以来都不是 PEP8 的刻板限制,从 2013 年开始,PEP8 就用各种细节描述提到可以扩展到 99 个字符,现在的版本是这样描述的:

Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the line length limit up to 99 characters, provided that comments and docstrings are still wrapped at 72 characters.

也就是看团队的约定,可以将行长度限制增加到最多 99 个字符,当然前提是注释和文档字符串不超过 72 个字符。

对于编程语言来说,代码格式化是最容易引起争议的一个问题。PEP8 存在的价值在于阻止开发者争论无关紧要的格式化规则,由官方提供一个良好的、被广泛认可的指南。做得更好的是 Golang,通过 gofmt 能把代码格式化成符合 Golang 语言要求的格式,开发者就可以将宝贵的时间专注在语言要解决的问题上。

说回来,官方提供的编码风格标准不可避免的会相对保守,就像用各种操作系统的发行版的包管理工具安装软件,默认参数都是中规中矩,很多时候都不适合在生产环境中直接使用。就拿 PEP8 的类型检查器 pycodestyle (原来的 pep8) 来说,默认就刻板的要求行的字符数不能超过 80,否则就抛错:

❯ pycodestyle  models/encourage.py
models/encourage.py:33:80: E501 line too long (80 > 79 characters)
models/encourage.py:86:80: E501 line too long (82 > 79 characters)
models/encourage.py:192:80: E501 line too long (83 > 79 characters)
models/encourage.py:193:80: E501 line too long (83 > 79 characters)

所以渐渐地很多 Python 开发者就有了一行最大长度最多79这种印象,这是不对的。

我的理由

PEP8 是在 2001 年制定的,我认为一开始限制每行字符数不应该超过 79 是由于当时电脑配置的限制,外「为什么选 79」我从 StackOverFlow 上找到了答案:

默认尺寸下的等宽字体打印(在 A4 纸上)为 80 列乘 66 行

这样就可以把代码显示良好的打印在纸上了。

但是现在无论是屏幕尺寸还是分辨率都获得了极大的提升,可读性不是问题,而业务逻辑的复杂度远超写指南的那个时代,变量名、函数名、三目运算符、列表 (字典) 解析等等点都非常容易最后让行超过 79,为了遵守这个规范换行很多时候反而降低了可读性,尤其是逻辑比较长,换行可能让这段逻辑超过一屏,还不如不换行好理解。

当然行的长度也不能特别长,因为绝大部分视情况已经有更好的时机提前换行了。我翻了下 CPython 代码,官方标准库里面很多模块,甚至新模块都没有遵守 79 字符数这个限制,如 dataclasses、pathlib、enum,mypy 也没有遵守。

那 2020 年的现在,长度定在多少最合适呢?为了确定这个我特意找了一些知名开源项目看他们怎么规定的:

  • black。默认的阈值是 88
  • requests。适当的可以达到 100 个字符,有必要可以超过 100
  • flask (Pocoo)。有必要可以扩展到 84
  • django。如果代码行看起来丑陋或难以阅读可以扩展到 119

阈值各不相同,但 79 显然不是一个企业开发中值得鼓励和坚持的长度阈值,我在日常工作中一般不超过 90 即可。

延伸阅读

  1. https://stackoverflow.com/a/89011/2202409
  2. https://github.com/psf/black/tree/master#command-line-options
  3. https://github.com/psf/requests/blob/master/docs/dev/contributing.rst
  4. https://github.com/pallets/flask/blob/2659f0a5e62c9a97ef37dc2ded3ca8fda3c53c9f/docs/styleguide.rst
  5. https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/