PEP 8とは(概要)
PEP 8 は、Pythonコードを書くときの公式スタイルガイドです。
主に「Python標準ライブラリで使うコーディング規約」として定義されていますが、一般的なPythonプロジェクトでも広く参照されています。
PEP 8で特に重要なのが、Guido van Rossumの次の考え方です。
コードは、書かれる時間よりも読まれる時間の方がはるかに長い。
つまり、コードを書くときは「自分が今わかるか」だけでなく、あとから読む人が理解しやすいか、保守しやすいか を重視する必要があります。
一貫性にこだわりすぎるのは、狭い心の現れである
ただし、PEP 8は絶対的なルールではありません。
PEP 8自身も、次のような考え方を示しています。
- プロジェクト内の一貫性を優先する
- 可読性を下げるくらいなら、規約から外れてもよい
- 既存コードのスタイルに合わせることも重要
つまり、PEP 8は「守るための規則」というより、読みやすく、保守しやすいPythonコードを書くための共通基準です。
PEP 8で定義されている内容
PEP 8では、主に以下のような内容が定義されています。
| 分類 | 内容 |
|---|---|
| コードのレイアウトに関するルール | インデント、空行、行の長さ、import文、式や文の空白など |
| コメントに関するルール | ブロックコメント、インラインコメント、ドックストリングスなど |
| 命名規約に関するルール | モジュール名、クラス名、関数名、変数名、定数名、非公開メンバーなど |
| プログラミング上の推奨事項 | 比較、例外、関数アノテーション、変数アノテーションなど |
この記事では、特に以下の3つに絞ってまとめます。
- コードのレイアウト
- コメント
- 命名規約
コードのレイアウト
インデント
PEP 8では、インデントは半角スペース4つ が基本です。
def greet(name):
print(f"Hello, {name}")
Pythonでは、インデントが構文上の意味を持ちます。
そのため、インデントの揺れは単なる見た目の問題ではなく、コードの意味そのものに影響します。
スペースとタブ
PEP 8では、タブよりもスペースが推奨されています。
# 良い例
def sample():
print("Hello")
タブは、既存コードとの一貫性を保つ場合に限って使う扱いです。
また、Pythonではインデントにタブとスペースを混在させることはできません。
1行の長さ
PEP 8では、すべての行の長さを 79文字 までに制限するように記載されています。
また、docstringやコメントについては、72文字 までに制限するようにすべきとあります。
これは、2つのファイルを並べて開いたときに、コードを折り返さずに閲覧することができるよにするための規約です。
また、プロジェクトチームとの合意のもと、1行を 99文字 まで制限を緩めることが許容されています。
複数行にまたがる場合
長い式を書く場合は、括弧 ()、角括弧 []、波括弧 {} を使った暗黙の行継続が推奨されています。
total = (
price
+ tax
+ shipping_fee
)
バックスラッシュ \ による行継続も使えますが、基本的には括弧を使う方が読みやすいです。
# あまり推奨されない例
total = price + \
tax + \
shipping_fee
空行
空行は、コードの論理的なまとまりを示すために使います。
文章でいう「段落」のようなものです。
PEP 8では、主に以下のような空行ルールがあります。
| 場所 | 空行の目安 |
|---|---|
| トップレベルの関数・クラス定義の前後 | 2行 |
| クラス内のメソッド定義の前後 | 1行 |
| 関数内の論理的な区切り | 必要に応じて少なめに使用 |
トップレベルの関数・クラス
トップレベルの関数やクラスは、2行空けます。
class User:
pass
def create_user():
pass
クラス内のメソッド
クラス内のメソッド同士は、1行空けます。
class User:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, {self.name}")
関数内の空行
関数内では、処理のまとまりを分けたいときに空行を使います。
def process_user(user):
name = normalize_name(user.name)
email = normalize_email(user.email)
if not email:
raise ValueError("email is required")
save_user(name, email)
空行を入れすぎると、かえって読みにくくなります。
「処理のまとまりを分けるために使う」と考えるのがよいです。
Import文
import文は、基本的にファイルの先頭にまとめて書きます。
また、通常は 1行に1つずつ 書きます。
# 良い例
import os
import sys
# 避ける例
import os, sys
ただし、from ... import ... で複数の名前を読み込む形は許容されます。
from subprocess import PIPE, Popen
import文の順序
import文は、次の順序でグループ化します。
グループ間には空行を入れます。
# 標準ライブラリ
import os
import sys
# サードパーティライブラリ
import pandas as pd
import requests
# 自作モジュール
from my_app.config import settings
from my_app.utils import normalize_text
基本的な順序は以下です。
- 標準ライブラリ
- サードパーティライブラリ
- 自作アプリケーション・自作ライブラリ
ワイルドカードimportは避ける
from module import * のようなワイルドカードimportは、原則として避けます。
# 避ける例
from math import *
この書き方は、どの名前が現在の名前空間に追加されたのか分かりにくくなります。
その結果、コードの可読性や保守性が下がります。
空白文字
空白文字は、可読性を高めるために使います。
ただし、余計な空白は避けます。
括弧の内側に余計な空白を入れない
# 良い例
spam(ham[1], {eggs: 2})
# 避ける例
spam( ham[ 1 ], { eggs: 2 } )
カンマ・セミコロン・コロンの直前に空白を入れない
# 良い例
print(x, y)
# 避ける例
print(x , y)
関数名と括弧の間に空白を入れない
# 良い例
print("hello")
# 避ける例
print ("hello")
代入演算子の周りには空白を入れる
# 良い例
count = 1
total = count + 10
# 避ける例
count=1
total=count+10
キーワード引数やデフォルト引数の = には空白を入れない
# 良い例
def connect(host, port=8080):
pass
connect(host="localhost", port=8080)
# 避ける例
def connect(host, port = 8080):
pass
connect(host = "localhost", port = 8080)
型アノテーションとデフォルト値を組み合わせる場合
型アノテーションとデフォルト値を組み合わせる場合は、= の前後に空白を入れます。
def greet(name: str = "Guest") -> None:
print(name)
コメント
PEP 8では、コメントについて次のような考え方が示されています。
コードと矛盾するコメントは、コメントしないことよりタチが悪いです
コードを変更したら、コメントも更新する必要があります。
古いコメントが残っていると、読み手はコードとコメントのどちらを信じればよいか分からなくなります。
コメントは、コードをそのまま説明するためではなく、主に以下を補足するために使います。
- なぜその処理をしているのか
- 背景事情は何か
- 注意すべき制約は何か
- 一見すると不自然な実装にした理由は何か
ブロックコメント
ブロックコメントは、対象となるコードの直前に書きます。
インデントは、そのコードと同じレベルに合わせます。
各行は # と半角スペース1つで始めます。
# ユーザー名が未入力の場合は、仮の名前を設定する。
# 外部API側で空文字がエラーになるため。
if not user_name:
user_name = "Guest"
複数段落に分けたい場合は、# だけの行で区切ります。
# ここでは住所文字列を正規化する。
#
# ハイフンや全角数字の揺れを吸収してから、
# 後続の住所比較処理に渡す。
normalized_address = normalize_address(address)
インラインコメント
インラインコメントは、コードと同じ行に書くコメントです。
PEP 8では、インラインコメントは控えめに使うべきとされています。
インラインコメントを書く場合は、文とコメントの間を少なくとも半角スペース2つ空け、# の後ろには半角スペースを1つ入れます。
x = x + 1 # 境界補正のため1加算する
次のように、コードを見れば分かることをコメントに書くのは避けます。
x = x + 1 # xに1を足す
これは、コメントが新しい情報を増やしていないためです。
コメントを書くなら、「何をしているか」よりも「なぜそうしているか」を書く方が有用です。
ドックストリングス
ドックストリングスは、モジュール・関数・クラス・メソッドの説明を書くための文字列です。
PEP 8では、ドックストリングスの詳細な規約は PEP 257 にまとめられています。
ドックストリングスは、対象オブジェクトの最初の文として書かれる文字列です。
def add(a: int, b: int) -> int:
"""Return the sum of a and b."""
return a + b
複数行のドックストリングスでは、概要行、空行、詳細説明の順に書きます。
終了側の """ は独立した行に置きます。
def calculate_total(price: int, tax_rate: float) -> int:
"""Calculate the total price including tax.
Args:
price: Base price.
tax_rate: Tax rate.
Returns:
Total price including tax.
"""
return int(price * (1 + tax_rate))
ドックストリングスには、三重のダブルクォート """ を使うことが推奨されています。
命名規約
PEP 8では、Pythonの命名規約について以下のような基準が示されています。
既存ライブラリには歴史的な揺れがありますが、新しく書くコードでは現在の推奨規約に従うのが基本です。
| 対象 | 命名スタイル | 例 |
|---|---|---|
| モジュール名 | 小文字、必要に応じて _
|
user_service.py |
| パッケージ名 | 小文字、短め | utils |
| クラス名 | CapWords / PascalCase | UserService |
| 例外クラス名 | CapWords、エラーなら Error 接尾辞 |
ValidationError |
| 関数名 | 小文字 + _
|
calculate_total() |
| 変数名 | 小文字 + _
|
user_name |
| メソッド名 | 小文字 + _
|
get_user_name() |
| 定数名 | 大文字 + _
|
MAX_RETRY_COUNT |
| インスタンスメソッド第1引数 | self |
def method(self): |
| クラスメソッド第1引数 | cls |
def method(cls): |
| 非公開メンバー | 先頭に _
|
_internal_value |
| キーワード衝突回避 | 末尾に _
|
class_ |
例です。
MAX_RETRY_COUNT = 3
class UserService:
def get_user_name(self, user_id: int) -> str:
user_name = "Shoji"
return user_name
避けた方がよい名前
l、O、I を1文字の変数名として使うことは避けます。
フォントによって、数字の 1 や 0 と見分けにくいためです。
非公開メンバー
Pythonには、JavaやC#のような厳密なprivateはありません。
ただし、先頭にアンダースコアを付けることで「内部利用の意図」を示します。
_internal_cache = {}
これは「外部から直接使わないでほしい」という慣習的なサインです。
静的解析ツール
PEP 8はコーディング規約なので、人間が毎回すべてを目視で確認するのは大変です。
実務では、静的解析ツールやフォーマッタを使って自動チェックするのが一般的です。
現在、多くのツールが Ruff に統合されています。ツールを個別に導入する手間や、実行速度の遅さに悩まされることがなくなります。
PEP 8 スタイルチェック・修正ツール一覧
| ツール名 | 分類 | 主な役割・特徴 |
|---|---|---|
| Ruff | リンター / フォーマッタ | 現在の主流。 Rust製で圧倒的に高速。 |
| Flake8 | リンター | 従来の定番。 |
| pycodestyle | リンター | PEP 8チェックの元祖。 (旧名 pep8)。 |
| Pylint | 総合静的解析 | 最も厳格。コードの品質を10点満点でスコア化する。 |
| Black | フォーマッタ | 自動整形の標準。「強制的に自動修正」する。 |
| isort | フォーマッタ | import文の専門家。 import文を自動で並び替える。 |
| pydocstyle | リンター | docstringの専門家。 |