Pythonのコードは動けばよいだけではありません。
読みやすく、保守しやすく、チームで一貫した書き方にすることが重要です。
そこで役立つのがPEP8という公式のスタイルガイドです。
本記事ではインデントや空白、命名、import、コメントの実務ルールまでを、初心者にもわかりやすく段階的に解説します。
PEP8とは?Pythonのコーディング規約の基本
PEP8の目的とメリット(可読性/一貫性)
PEP8はPythonの公式スタイルガイドで、コードの見た目や書き方を標準化するための文書です。
目的は可読性の向上と一貫性の確保にあります。
統一された書き方は、レビューやバグ修正を速くし、チーム開発の認知コストを下げます。
Pythonは「読みやすさ」を重視する言語であり、PEP8はその精神を具体的なルールに落とし込んだものです。
適用範囲と優先順位(プロジェクト規約/公式規約)
PEP8はあくまで一般ガイドラインであり、絶対ではありません。
基本方針は次の通りです。
まずプロジェクトで定めた規約が最優先です。
次にPEP8、最後に個人の好みの順に従います。
たとえば行の長さについてはPEP8の79文字を採るか、ツールの既定幅(例: black
の88文字)に合わせるかをプロジェクトで決めて統一します。
チーム内で混在することこそが最大の読みづらさにつながります。
ツールで自動化(flake8/black/isort)
人力で全てのルールを守るのは大変です。
次のツールで自動化しましょう。
静的チェックはflake8
、自動整形はblack
、import順の整列はisort
が定番です。
エディタ保存時に走らせると効果的です。
# 導入例
pip install flake8 black isort
# チェックと整形
flake8 .
black .
isort .
設定はpyproject.toml
にまとめると管理しやすく、チームで共有できます。
# pyproject.toml の例
[tool.black]
line-length = 88
target-version = ["py39"]
[tool.isort]
profile = "black" # blackと揃える
[tool.flake8]
max-line-length = 88
extend-ignore = ["E203", "W503"] # blackと競合するルールを無効化
インデント・空白・改行のルール(PEP8)
インデントは4スペース(タブ禁止)
Pythonはインデントが構文の一部です。
PEP8はインデントは4スペース、タブは使用禁止としています。
エディタの設定でTabキーをスペースに変換しましょう。
# 悪い例: タブや2スペースはNG
def greet():
\tprint("Hello") # タブによるインデント
print("World") # 2スペース
# 良い例: 4スペースに統一
def greet():
print("Hello")
print("World")
- 関連記事:スクリプト(.py)作成と実行の基本手順
行の長さは79文字(コメント/Docstringは72文字目安)
コードの横スクロールは読みづらさの原因です。
PEP8はコードは79文字、コメントやDocstringは72文字を推奨します。
プロジェクトで88文字などに緩和する場合はルールを全体で統一します。
# 長すぎる行は避ける
message = "..." # 79文字を目安に。長い式や引数は次の節のように折り返します。
行継続は括弧で行う(バックスラッシュは避ける)
式の折り返しは括弧((), [], {})で行います。
バックスラッシュによる行継続は原則避けるのが安全です。
# 良い例: 括弧での暗黙的改行
numbers = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
]
total = sum(
x for x in numbers
if (x % 2 == 0 and x > 3)
)
# 悪い例: バックスラッシュは保守性が低い
# total = sum(x for x in numbers \
# if x % 2 == 0 and x > 3)
空白の使い方(演算子/カンマ/コロンの前後)
空白は読みやすさに直結します。
二項演算子の前後にはスペースを1つ入れ、カンマやコロンの前にはスペースを入れず、後ろに入れます。
# 良い例
x = 1 + 2
point = (x, y) # ← ダブルスペース? ダメです。後述の余計な空白へ
mapping = {"a": 1, "b": 2}
for i in range(3):
pass
# 悪い例
x=1+2 # 演算子の前後にスペースなし
point = (x , y) # カンマの前にスペース
for i in range (3): # 関数名と引数の括弧の間にスペース
pass
余計な空白は禁止(行末/括弧直後・直前)
行末の空白は削除します。
括弧の直後や直前に空白を入れるのも禁止です。
また、=
で代入やキーワード引数を書くときは、=
の前後にスペースを入れるのは場面で異なります。
- 代入:
x = 1
のように前後にスペースを入れます。 - キーワード引数やデフォルト引数:
func(x=1)
、def f(x=1):
のようにスペースなしが原則です。
# 良い例
values = [1, 2, 3] # ← 行末の空白なし
area = width * height
user = dict(name="Alice", active=True)
# 悪い例
values = [ 1, 2, 3 ] # 括弧直後・直前の空白
area = width*height # 二項演算子の前後に空白なし
greet(name = "Bob") # キーワード引数でスペースを入れている
空行の数(トップレベル2/クラス内1)
モジュール直下の関数やクラスは2行で区切ります。
クラス内のメソッド同士は1行で区切ります。
# トップレベル関数は2行で区切る
def load_data():
pass
def process():
pass
class Service:
def __init__(self) -> None:
pass
def run(self) -> None:
pass
エンコーディング宣言は原則不要(UTF-8既定)
Python 3ではソースはUTF-8が既定です。
特殊な事情がない限り# -- coding: utf-8 --
は不要です。
異なるエンコーディングを使う場合のみファイル先頭に宣言します。
命名規則 PEP 8の要点
PEP 8は、Pythonコードの可読性を高めるための公式なスタイルガイドです。
その中でも命名規則は、コードの意図を明確に伝え、誰が読んでも理解しやすくするための重要なルールを定めています。
最も大切な原則は、プロジェクトやチーム内で一貫性を保つことです。
たとえPEP 8と異なるスタイルであっても、既存のコードと統一されていることが優先される場合もあります。
ここでは、PEP 8が推奨する標準的な命名スタイルを詳しく見ていきましょう。
パッケージ名とモジュール名は短く、スネークケースで
モジュールやパッケージの名前には、短く、すべて小文字のsnake_case
(単語間をアンダースコア_
でつなぐ形式)を使用します。
これにより、インポート文が簡潔で読みやすくなります。
- 良い例:
my_package
,data_processing.py
,http_client.py
- 悪い例:
MyPackage
,dataprocessing
,http-client.py
名前の先頭に数字は使えず、ハイフン (-
) などの特殊文字も避けるべきです。C/C++で書かれた拡張モジュールなど、特殊なケースでは先頭に_
を付けることもあります。
クラス名はキャメルケース(CapWords)で
クラス名は、各単語の先頭を大文字でつなげるCapWords
(PascalCase
とも呼ばれます)で記述します。
これにより、関数や変数(インスタンス)と視覚的に明確に区別できます。
- 良い例:
MyClass
,HttpRequest
,DatabaseConnection
- 悪い例:
my_class
,http_request
例外クラス名は「Error」で終える
自分で定義する独自の例外クラスは、通常のクラスと同様にCapWords
を使い、さらに接尾辞としてError
を付けることが強く推奨されます。
これにより、そのクラスが例外処理のためのものであることが一目でわかります。
- 良い例:
ValidationError
,ConnectionTimeoutError
関数、メソッド、変数はスネークケースで
コードの中で最も頻繁に登場する関数、メソッド、変数の名前は、すべて小文字のsnake_case
で統一します。
これがPythonにおける最も標準的なスタイルです。
- 関数:
def calculate_total_price():
- メソッド:
def get_user_data(self):
- 変数:
user_name = "Taro"
,item_list = []
定数は大文字のスネークケースで
プログラムの実行中に値が変更されることを意図しない定数は、すべて大文字のUPPER_CASE_SNAKE
で表現します。
これにより、通常の変数と区別し、意図しない再代入を防ぐ注意喚起になります。
定数は通常、モジュールのトップレベルで定義されます。
- 良い例:
MAX_OVERFLOW_CONNECTIONS = 10
,SUPPORTED_VERSIONS = ("1.0", "1.1")
内部利用の要素は先頭にアンダースコア _ を付ける
クラスの内部でのみ使用するメソッドや変数など、外部からの直接的なアクセスを想定していない要素には、先頭にアンダースコアを1つ (_single_leading_underscore
) 付ける慣習があります。
これはPythonの文法として強制力を持つものではありませんが、「これは内部用の実装であり、将来的に変更される可能性がある」ことを他の開発者に伝えるための重要なヒントとなります。
また、from module import *
という形式のインポートでは、この_
で始まる名前はインポート対象外となります。
- 例:
_internal_variable
,def _helper_function(self):
予約語と名前が衝突する場合は末尾に _ を付ける
変数名や引数名として使いたい単語が、Pythonの予約語(class
, def
, for
など)と重複してしまう場合があります。
その際は、名前の末尾にアンダースコアを1つ (trailing_underscore_
) 付けることで衝突を回避します。
- 例:
class_ = "MyClass"
,def format_data(data, id_):
__で囲まれた名前(dunder名)は独自に定義しない
__init__
や__str__
のように、名前の前後がアンダースコア2つで囲まれている名前は、dunder名 (Double UNDERscore names) と呼ばれます。
これらは、Pythonの言語仕様で特別な意味を持つために予約されています(例: 演算子のオーバーロード、オブジェクトの文字列表現など)。
意図しない動作や将来のバージョンでの衝突を避けるため、ユーザーが独自にこの形式の名前を定義するべきではありません。
Pythonが提供する特殊メソッドをオーバーライドする場合にのみ使用してください。
下表に要点をまとめます。
対象 | 推奨形式 | 例 |
---|---|---|
パッケージ/モジュール | snake_case | utils, data_loader |
クラス | CapWords | DataLoader, HttpClient |
例外クラス | CapWords + Error | DataFormatError |
関数/メソッド/変数 | snake_case | load_data, parse_json |
定数 | UPPER_CASE | DEFAULT_TIMEOUT |
非公開 | 先頭に_ | _internal_cache |
予約語回避 | 末尾に_ | class_, type_ |
特別メソッド | dunder(予約) | __init__, __enter__ |
# 命名の例
MAX_RETRY = 3 # 定数
class DataFormatError(Exception): # 例外はErrorで終える
pass
class DataLoader: # クラスはCapWords
def __init__(self, source: str) -> None:
self._source = source # 非公開属性は先頭に_
def load_data(self) -> list[str]: # 関数/メソッドはsnake_case
return ["a", "b", "c"]
def class_(name: str) -> str: # 予約語回避
return f"class: {name}"
インポート・比較・コメントなどの実務ルール
importはファイル先頭でグループ化(標準/サードパーティ/自作)
importは基本的にファイル先頭にまとめ、標準ライブラリ、サードパーティ、自作の順にグループ化し、グループ間は空行で区切ります。
アルファベット順に並べると衝突が減ります(isort
で自動化可)。
# 良い例
from __future__ import annotations # 必要なら最上位
import json
import pathlib
import requests
from .utils import parse_json
importのスタイルは明確に(from x import yは必要最小限)
ワイルドカード*
のimportは避けるべきです。
from x import y
は必要最小限にし、名前の衝突を避けます。
別名が必要ならas
を使います。
# 悪い例
# from math import * # 何が入るか不明瞭
# 良い例
import math
from math import sqrt # 必要なものだけ
import numpy as np # 衝突回避や慣習に沿った別名
None/True/Falseとの比較はis/is not
同一性で比較すべき対象はis
/is not
を使います。
特にNone
は==
ではなくis
で比較します。
# 良い例
if value is None:
handle_missing()
# 悪い例
if value == None: # noqa: E711
handle_missing()
ブール比較は冗長にしない(if flag:)
ブール値に対して明示的な比較(== True
)は不要です。
コレクションの空判定は直接真偽値に評価します。
# 良い例
if flag:
...
if items: # 空ならFalse
...
# 悪い例
if flag == True:
...
if len(items) > 0:
...
文字列クォートはプロジェクト内で統一
シングル引用'
とダブル引用"
のどちらでも構いませんが、プロジェクト内で統一します。
自動整形ツール(black
)に従うのも有効です。
title = "Hello" # どちらかに統一
name = "Alice"
行内コメントは控えめに(コードとの間に2スペース)
行内コメントはコードと#
の間に2スペースを入れ、必要な場合に限定します。
冗長なコメントは避け、なぜそう書くかを説明します。
threshold = 0.8 # 実運用での誤報率に基づく経験値
Docstringは三重引用で記述(モジュール/クラス/関数)
ドキュメンテーション文字列は三重引用"""
で書き、1行目に要約、空行、詳細の順にします。
関数の引数や戻り値の説明はプロジェクトのスタイル(Google/Numpy/reST)に合わせます。
"""データ読み込みモジュール。
外部APIからJSONを取得してモデルに取り込みます。
"""
from __future__ import annotations
from typing import Any
class Client:
"""APIクライアント。
Attributes:
endpoint: ベースURL。
"""
def __init__(self, endpoint: str) -> None:
self.endpoint = endpoint
def fetch(self, path: str) -> dict[str, Any]:
"""指定パスからJSONを取得して辞書で返します。
Args:
path: エンドポイント以下のリソースパス。
Returns:
APIレスポンスの辞書。
"""
# 実装は省略
return {"status": "ok"}
参考として、Docstringを整形して出力する簡単なデモを示します。
# docstring_demo.py
def add(a: int, b: int) -> int:
"""2つの整数を足し合わせて返します。"""
return a + b
if __name__ == "__main__":
print(add.__doc__)
print(add(2, 3))
2つの整数を足し合わせて返します。
5
まとめ
PEP8はPythonにおける読みやすさと一貫性の共通言語です。
インデントは4スペース、空白と改行の配置、命名規則、importの整理、コメントやDocstringの書き方を押さえることで、初学者でもプロ品質に近づけます。
さらにflake8/black/isortで自動化すれば、手作業の負担を減らしつつ規約順守を徹底できます。
プロジェクトで例外を設ける場合も、ルールを明文化して全員で統一しましょう。
今日からエディタに整形とチェックを設定し、クリーンなコードベースを育てていくことをおすすめします。