Python で 1 行が 79 文字以内で、インデントがスペース 4 文字なのはなんで?

PEP 8 にそう書いてあるから

すべての行を最大 79 文字に制限する。
Limit all lines to a maximum of 79 characters.
PEP 8 -- Style Guide for Python Code

インデントには 4 文字の半角スペースを使ってください。
Use 4 spaces per indentation level.
PEP 8 - Style Guide for Python Code


以下、なぜ PEP 8 でそのように定められているのかについて調べたり、 考えたりして見ました。

PEP 8 がどのような文章なのかについては、 こちらにまとめさせていただきました。





1 行が 79 文字以内である理由

エディタに勝手に
改行させないため。

コードレビューする際に、エディタで勝手に改行されると読みづらくなるので。

この 1 行の文字数の制限は、 1 行が 80 文字のエディタが折り返して表示する機能を避けるために選定されたものである。
PEP 8 - Style Guide for Python Code

また単純に横に長すぎると読み辛いということかなと思ったりもします。 適切に抽象化してなっていうそういう意味合いかなと思ったりもします。 以下は  PEP 7  という Python のインタープリタ本体を書くときの C 言語のコーディング規約からの引用になります。

PEP 7 - Style Guide for C Code

  • 4 文字のスペースをインデントとして使い、決してタブを使ってはいけない。
    Use 4-space indents and no tabs at all.

  • 1 行につき 79 文字を超過してはいけない。 No line should be longer than 79 characters.

もし 1 行 79 文字のルールとこの前の 4 文字スペースのインデントのルールでコードを書くのが厳しいならば あなたのコードは複雑すぎるということだ -- 関数を使うことを考えてください。
If this and the previous rule together don't give you enough room to code, your code is too complicated -- consider using subroutines.

あとタブを使ってはいけないのは、 パソコンの環境によって表示が変わってしまうからだと思っています。 環境によってタブが2文字で表示されたり、 4文字で表示されたりします。

◯ PEP 7 - C 言語のコーディング規約

実は標準ライブラリには Python で書かれたものと C 言語で書かれていものがあります。

C 言語で書かれたコードを import して Python で使えるの?という疑問はありますが、 とりあえず、いまは使えるということだけ押さえておいてください。 math は C 言語で書かれています。

C 言語で書かれた標準モジュールには PEP 7 というコーディング規約が存在します。 PEP 8 の冒頭で書かれている「C言語のスタイルガイドを記した PEP」とは PEP 7 のことを指しています。

CPython に含まれるC言語のコード [1] については、 対応する C 言語のスタイルガイドを記した PEP を参照してください。
[1] PEP 7, Style Guide for C Code, van Rossum
Python コードのスタイルガイド - PEP 8

◯ 80 文字という数字は、どこから来たの?

ちなみにこの 80 という数字はパンチカードから来ているのでは、 という話を聞いたことがあります。

1928年、IBMは縦長の長方形の穴を採用し、 80欄で各欄に12のパンチ位置があり、1欄(コラム)で1文字を表す形式のカードを設計した[23]。
パンチカード - Wikipedia

あんまり関係ないけど面白いです。

日経電子版と朝日新聞デジタルは21文字以上40文字未満のあたりにピークが来ますが、 NHKは60文字以上80文字以下を中心に、綺麗なカーブって感じですね。
読みやすい文章の長さとは? 一文の長さを調べてみた。

◯ どのくらいの温度感なの?

結構厳しい制限ですが、どれくらいの温度感なのでしょうか? Python で最初からはいっているモジュールで Python で書かれたものは、基本的には 79 文字以内に限定されています。

Python の標準ライブラリは保守的であり、79 文字以内に限定されていなければなりません (また docstring や コメントは 72 文字以内に限定されています。)
The Python standard library is conservative and requires limiting lines to 79 characters (and docstrings/comments to 72).
PEP 8 - Style Guide for Python Code

ここで言う標準ライブラリとは import すると使える機能のうち Python で書かれたコードを指しています。 具体的には下記の URL 先のコードです。

ただ 型アノテーションを使うときは相当苦しいという意見を見ます。

◯ PEP 8 和訳

PEP 8 のうち Maximum Line Length 抜粋、和訳しました。

1行の最大行数 - PEP 8
Maximum Line Length - PEP 8

すべての行を最大 79 文字に制限する。
Limit all lines to a maximum of 79 characters.

コードの後に続く docstring やコメントのような構造的な制限の少ない長いブロックのテキストについては、 1 行の長さは 72 字以内にするべきだ。
For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 72 characters.

エディタのウィンドウを表示する際に必要な幅を制限できれば、 複数のファイルを並べることが可能になり、 2 つのバージョンのコードを隣接して左右に並べて、 コードリビューツールを使うときに効果的である。
Limiting the required editor window width makes it possible to have several files open side-by-side, and works well when using code review tools that present the two versions in adjacent columns.

大抵のツールが提供する、デフォルトで長い 1 行を折り返して表示してくれる機能(wrapping)は、 コードの見た目の構造を破壊し、より理解を困難なものにする。
The default wrapping in most tools disrupts the visual structure of the code, making it more difficult to understand.

この 1 行の文字数の制限は、1 行が 80 文字のエディタが折り返して表示する機能を避けるために選定されたものである。 もし、たとえツールが目印として 1 行の文字を複数行で折り返し表示したときに、 最後の文字に印を置いてくれるような機能がったとしても 勝手に折り返されるのを避けるために1行を 79 文字に制限するべきである。
The limits are chosen to avoid wrapping in editors with the window width set to 80, even if the tool places a marker glyph in the final column when wrapping lines.

いくつかのウェブベースのツールは、自動的に行を折り返してくれるようなことは、全くしてくれないかもしれない。
Some web based tools may not offer dynamic line wrapping at all.

チームによっては、もっと長い行で書きたいと強く思うかもしれない。 この問題について同意に達することができるチームだけが、あるいはそのチームがおもに、保守運営するようなコードに対しては 名目的な文字数の上限を 80 文字から 100 文字に引き上げてもいい(実質な文字数の上限は 99 文字の長さまで伸ばしても良いことになる)、 ただし、コメントと docstring は 72 文字以内のままであると言う条件には、従わねばなりません。
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 nominal line length from 80 to 100 characters (effectively increasing the maximum length to 99 characters), provided that comments and docstrings are still wrapped at 72 characters.

Python の標準ライブラリは保守的であり、79 文字以内に限定されていなければなりません (また docstring や コメントは 72 文字以内に限定されています。)
The Python standard library is conservative and requires limiting lines to 79 characters (and docstrings/comments to 72).

1行を複数行に分けて書く方法として望ましいものは、 括弧 parentheses ()、中括弧 braces {}、大括弧 brackets [] を使えば Python では暗黙的に行を継続できることを活用することです。
The preferred way of wrapping long lines is by using Python's implied line continuation inside parentheses, brackets and braces.

長い行は、括弧で括られた式によって、複数行に分割させることができます。 バックスラッシュで行を継続させるよりも、括弧を使って行を継続させた方が望ましいです。
Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.

バックスラッシュは、時と場合によっては、適切かもしれません。 例えば、長い multiple with-statements は暗黙的に行を継続することができないので バックスラッシュを使うことが望ましいです。
Backslashes may still be appropriate at times. For example, long, multiple with-statements cannot use implicit continuation, so backslashes are acceptable:

with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

(multiline with-statement のインデントに関するさらなる考察は、 上記で議論された multiline if-statement を参照してください。)
(See the previous discussion on multiline if-statements for further thoughts on the indentation of such multiline with-statements.)

他の例としては assert 文があります。
Another such case is with assert statements.

行を折り返した場合は適切にインデントがなさるようにしてください。
Make sure to indent the continued line appropriately.

インデントが 4 文字である理由

インデントが 4 文字のスペースである理由、インデントが 2 文字のスペースではない理由



Flat is better than nested.
ネストは浅い方が良い

PEP 20 - The Zen of Python

インデントには 4 文字の半角スペースを使ってください。
Use 4 spaces per indentation level.

PEP 8 - Style Guide for Python Code

ただでさえ 79 文字で制限されているのに 4 文字でインデント作れとか、 どんだけ縛りプレイなんや、とか思ったりもしました。

逆にインデントを深くするなということなのかなと、最近、個人的に思うようになりました。 インデントが深くなった処理は関数にまとめて浅くすることができます。

ネストが浅い方が良いというのは「循環的複雑度」という言葉である程度、規定されてるのかな...



尊敬するフリをして煽ってくるスタイル

1 行を最大 79 文字以内に抑える方法

1 行 79 文字と言う制限が、実は結構重くて最初は無視するような設定にしようかと思っていたのですが、最近は遵守しています。いくつか回避方法があります。

1. バックスラッシュ \ を使う。

def eq(rectangle_a, rectangle_b):
    """2つの長方形が同じかどうかを確認する関数"""
    return \
        rectangle_a.x1 == rectangle_b.x1 and \
        rectangle_a.y1 == rectangle_b.y1 and \
        rectangle_a.x2 == rectangle_b.x2 and \
        rectangle_a.y2 == rectangle_b.y2

PEP 8 でもバックスラッシュ \ よりも括弧 ( ) を使ってねと書かれてましたが、 実は Guido は、バックスラッシュ \ は使って欲しくないそうです。 理由は書かれていないですが、確かに汚いですね。 かわりに 括弧 ( ) を使うように言っています。

· continued lines or strings with <br>

2. 括弧 ( ) を使う

括弧内なら改行が許容されます。

def eq(rectangle_a, rectangle_b):
    return all(
        rectangle_a.x1 == rectangle_b.x1,
        rectangle_a.y1 == rectangle_b.y1,
        rectangle_a.x2 == rectangle_b.x2,
        rectangle_a.y2 == rectangle_b.y2,
    )

文字列連結では、こんな書き方ができます。

# 1. str として格納される。tuple に格納される訳ではない。
# 2. + 演算子はいらない。
allowed_chars= ('abcdefghijklmnopqrstuvwxyz'
                'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')

3. 変数を分ける

個人的にはこんな感じで別の変数に一旦格納して2行に分けたりもします。これはこれで変数が増えてしまうのですが..。

# 前
supplier = Supplier.objects.filter(category=supplier_category).order_by('phonetic')

# 後
supplier = Supplier.objects.filter(category=supplier_category)
supplier_ordered_by_phonetic = supplier.order_by('phonetic')

4. 関数にする

例えばネストが深くなってしまった時は関数にしてネストから外してしまえば良いと思います。

  • 4 文字のスペースをインデントとして使い、決してタブを使ってはいけない。
    Use 4-space indents and no tabs at all.

  • 1 行につき 79 文字を超過してはいけない。 もし 1 行 79 文字のルールとこの前の 4 文字スペースのインデントのルールでコードを書くのが厳しいならば あなたのコードは複雑すぎるということだ -- 関数を使うことを考えてください。
    No line should be longer than 79 characters. If this and the previous rule together don't give you enough room to code, your code is too complicated -- consider using subroutines.

PEP 7 - Style Guide for C Code

5. 抽象化の度合いあげる。

Python には抽象化度合いをあげる様々な機能が提供されています。 例えば、iterator, descriptor, operator overload などです。 これらを使って短くすることができます。

>>> for member in team.member_list:
...     print(member)
川島 永嗣
香川 真司
長谷部 誠 
>>>
>>> for member in team:  # <-- ちょっとだけ短くできる。
...     print(member)
川島 永嗣
香川 真司
長谷部 誠 
>>>

6. 変数名を短くする

書籍「Readable Code」では、変数名の長さについて、 他の人が1度読めばわかるかどうかで、 変数名の長さを決めるように書かれています。

6.1. 変数名の長さによるメリット、デメリット

変数名が長い

  • メリット 読めばわかる。
  • デメリット 読みたくない(読めばわかるんだけど...)

変数名が短い

  • デメリット 読んでもわからない
  • メリット 読んでもいいかな、と思う

もちろん変数名が長い方が、理解できるコードになります。 ただ、その分コードが長くなって、 読むのが精神的に辛いコードになってしまいます。

そのせいかわからないのですが、可読性について議論する時に、 長い変数名を使うと、比較的炎上しやすい気がします。 テストコードならいいんじゃない?って思ったりもするのですが...

6.2. 変数名の長さを決める判断基準

  1. 使われる頻度
  2. スコープの広さ
  3. コードそのものの理解のしやすさ。
6.2.1. 使われる頻度が頻繁にあるなら

短くてもいいのかなと思います。 例えば、組み込み関数や組み込み型は、 総じて省略された短い名前です。たとえば len です。 これが length だったら、書くのも面倒です、読むのも煩雑です。

逆に、テストコードとかなら長くてもいいかなと思います。 以下の記事はすこし炎上気味ですが、テストコードとかなら、 関数名長くてもいいかなと。

ドキュメントを読みに行く煩雑さと 関数名を読む煩雑さを天秤にかける作業かなとも感じたりもします。

6.2.2. スコープが狭いなら

短くてもいいのかなと思います。 背景を共有している場合、逆に自明なことを記載すると冗長に感じます。

6.2.3. もし単純なコードなら

短くてもいいのかなと思います。 反対に、複雑なものが書かれたものであれば、 ある程度詳細に書いた方が望ましいと感じます。

コードの理解のしやすさと言うのは、 0...10 までの和を求めるような普遍性の高いもの。 理解しにくいとは、業務ロジックのような普遍性の低いもの。

以下の記事は 0 ... 100 までの偶数の和を求めるのに、 長い変数名を使い炎上しました。

このコードについては Python のコードを使い以下の記事で解説させていただきました。

6.3. まとめ

長い変数名は良し悪しに関わらず炎上しやすい気がします。 完全に憶測ですが、 それは読む側の日常の業務の負担から来るイライラを想起させるからかなと思います。

そのため、もし短くしても他の方が理解できるなら、 短く書いた方がいいのかなと思います。

そのため、すでに読み手が理解しているものは、 変数名には記述せずに削除してしまうのが望ましいような気もしたり、しなかったりします。