Pythonのコーディング規約を調査しました

2023/08/12に公開

各言語には必ずある「コーディング規約」ですが、Python にはどの様なものがあるのでしょうか。

Python のコーディング規約として「PEP 8」があります。

これを全て読み解くのは大変なので基本的なことだけをピックアップします。

始めに総論

  • インデントは 4 スペースを利用する
  • 関数の引数が複数ある場合は統一された方法で折り返す
    • 関数の開きカッコに揃える
    • 関数の 1 行目に引数を書き、その位置に 2 行目以降を合わせる
    • 1 行目には引数を置かず、追加のインデントを含める
  • 波括弧/ブラケット/括弧の位置は統一された方法でおく
    • リストの最後の要素が置かれた行の、はじめの文字の直下におく
    • 閉じる記号を継続された行のはじめの文字に合わせて置く
  • タブではなく、スペースを利用する。混在は不可能
  • 一行の長さは 79 文字、プロジェクトによって臨機応変に変更しても良い
  • ドキュメントは 72 文字まで
  • 改行時は2項演算子の前で改行する
  • トップレベルの関数やクラスは2空白行開ける
  • import 文は行を分ける
    • 1 つのモジュールから複数メソッドを利用する時は、一行で記載してよい
  • メソッドの括弧内等で余計な空白文字は使わない
  • 関数の引数にデフォルト値を入れるものについては、空白なしとする
  • デフォルト値をもった引数アノテーションと組み合わせる場合、 = の前後にはスペースを入れる
  • 命名規則に則り定義すること
  • 内部でしか利用しない変数やメソッドにはアンダースコアを 1 つ接頭辞としてつける

コードレイアウト

インデント

Python では、1 インデントに対し、4 つのスペースを使う様に指示されています。

特に関数の引数が複数ある場合、どこでインデントさせるかという議論になりますが、方法は複数あります。

  • 関数の開きカッコに揃える
  • 関数の 1 行目に引数を書き、その位置に 2 行目以降を合わせる
  • 1 行目には引数を置かず、追加のインデントを含める
# 正しい:

# 開き括弧に揃える
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 関数の 1 行目に引数を書き、その位置に 2 行目以降を合わせる
def long_function_name(
    var_one,
    var_two,
    var_three,
    var_four):
    print(var_one)


result = some_func(
    long_var_name1,
    long_var_name2,
    long_var_name3)


# 間違い:

# 折り返された要素を縦に揃えない場合、1行目の引数は禁止
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# インデントが区別できないので、2行目以降でさらにインデントが必要
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

if 文の条件で条件文が長い時、2つ目の条件をインデントするが、その場合4スペース分インデントされることになります。

その場合、if 文の条件文なのか、処理文なのかを区別しにくくなります。

if 文に含まれるネストされたコードの部分と、継続された条件部分を区別するかどうかについては特に指定はなさそうです。

個人的には、3つ目がわかりやすいと感じます。

# 追加のインデントをしない
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# シンタックスのハイライトをサポートするエディタで区別するため
# コメントを追加する
if (this_is_one_thing and
    that_is_another_thing):
    # 両方の条件がtrueなので、処理を調整可能
    do_something()

# 継続された行の条件をインデントする
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

波括弧/ブラケット/括弧の位置

これは、下記どちらでもいいと書かれているが、私は後者が好みです。

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]

my_list = [
    1, 2, 3,
    4, 5, 6,
]

タブかスペースか

スペースが好ましいとされています。

タブを使うのは、既にタブでインデントされているコードと一貫性を保つためだけです。

Python では、インデントにタブとスペースを混ぜることを禁止しています。

一行の長さ

最大 79 文字まで、それ以上はインデントで折り返す様にする。

docstring やコメントは 72 文字に制限されている。

2項演算子を使った改行

2 項演算子で複数使われている時、どこで改行するかについては、2 項演算子の前で改行する様にします。

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

これが 2 項演算子の後で改行すると、どこで加減算されているのかわかりにくくなります。

income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

トップレベルの空白行数について

トップレベルの関数やクラスは2空白行開けることになっています。

また、クラス内部では、1 行ずつ空けてメソッドを定義するようになっています。

import行の記載

import 文は、通常は行を分けるべきとされています。

例えば、os と sys モジュールを import する際、二行で記載する必要あります。
これは、JavaScript でも同様ですね。

しかし、1 つのモジュールから複数関数を利用する記載方法は、1 つに纏めて OK とされています。

# 正しい:
import os
import sys
# 悪い:
import sys, os


しかし、次のやり方は OK です:
from subprocess import Popen, PIPE

また、import は相対 import ではなく、絶対 import を使う様に推奨されています。

式や文中の空白文字

余計な空白文字は使わない様にします。

# 正しい:
spam(ham[1], {eggs: 2})
# 間違い:
spam( ham[ 1 ], { eggs: 2 } )

if 文ではその直後の括弧は空白行ですが、関数呼び出しの引数リストをはじめる開き括弧の直前は空白なしとしています。

# 正しい:
spam(1)
# 間違い:
spam (1)

特に下記に関しては、後者の方が見やすい場面もあります。
こちらに関してはプロジェクトの方針に沿った方が良さそうです。

# 正しい:
x = 1
y = 2
long_variable = 3

# 間違い:
x             = 1
y             = 2
long_variable = 3

また、もう 1 つややこしい点として、関数の引数にデフォルト値を入れるものについては、空白なしとしています。

# 正しい
def test(sample, log=False):

# 間違い
def test(sample, log = False):

しかし、デフォルト値をもった引数アノテーションと組み合わせる場合、 = の前後にはスペースを入れるようにします。

# 正しい:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...

末尾カンマ

末尾にカンマをつけるのは、要素数が 1 つ以上のタプル型を作る時は必須となります。

# 正しい:
FILES = ('setup.cfg',)
# 間違い:
FILES = 'setup.cfg',

コメント

docstring については PEP257 にまとめられている様です。

簡単なルールとしては下記の通りです。

  • 全てのクラスや関数やメソッドには記載する
  • 複数行の docstring は「"""」の行で閉じる
  • docstring が 1 行で終わる場合は、同じ行を「"""」で閉じる

命名規則

対象 ルール 一例
クラス アッパーキャメルケース MyCustomClass
関数 スネークケース my_custom_function
変数 スネークケース my_custom_variables
定数 大文字のスネークケース MY_CUSTOM_CONST
例外 アッパーキャメルケース MyCustomException
型変数 アッパーキャメルケース MyCustomType
private スネークケースに_を一つつける _my_custom_variables

関数やメソッドに渡す引数

インスタンスメソッドのはじめの引数の名前は常にselfを使います。

クラスメソッドのはじめの引数の名前は常にclsを使います。

アンダースコア2つの意味

今まではアンダースコア 2 つつけると private という意味を持つと思っていたのですが、それは違っている様です。

名前の最初をアンダースコア 2 個にすると、名前のマングリング機構(名前修飾)が働き、クラス固有の名前になります。

サブクラスで同じ名前を再定義しても別物として扱われ、サブクラスでの再定義(名前衝突)による影響を受けなくなるようです。

しかし、アンダースコア 2 個にしたのが原因で意図しない動作結果になることもあるため、あまりお勧めしないのではと思っています。

実際の運用

また上記のコーディング規約を守るためのツールとして「flake8」というものがあります。

これをエディターに導入することでチェックしながら開発もできます。

次回はこの flake8 について調べてみます。

GitHubで編集を提案

Discussion