Pythonのコードは動けば良いわけではありません。
読みやすく、レビューしやすく、長期的に保守しやすいことが大切です。
本記事では、Pythonの公式スタイルガイドであるPEP8の要点を、命名、インデントと空白、importの順序という3本柱で、初心者の方にもわかりやすく実例つきで解説します。
PEP8とは Pythonのコーディング規約の基本
PEP8は、Pythonコミュニティが合意した「こう書くのが一番読みやすい」という作法をまとめた文書です。
文法ではなく「見た目の取り決め」が中心で、コードの品質と協調開発の効率を高めます。
PEP8の目的
読みやすさと一貫性
PEP8の最優先事項は、読みやすさの向上です。
見た目がそろっていれば、初見のコードでも意図を掴みやすくなります。
同じプロジェクト内でスタイルが統一されていると、作業者が変わっても理解や変更が容易になります。
チーム開発とレビュー効率
スタイルが統一されていると、コードレビューではロジックに集中できます。
余分な指摘(スペースや改行の揺れ)を減らし、コミット履歴も小さく保てます。
適用範囲
何に適用されるか
PEP8は、以下の見た目や構造に関するルールを定めます。
- 命名規則(変数、関数、クラス、定数、モジュールなど)
- インデントや空白の入れ方、行長
- importの方法と順序
- 空行の入れ方、ファイル末尾の改行 など
適用しない場面の例
実行速度やメモリ効率などの性能要件はPEP8の範疇ではありません。
また、プロジェクト固有の方針でPEP8を上書きすることもあります。
ただし、正当な理由がなければPEP8に従うのが基本です。
補助ツールの活用
PEP8準拠を手で守るのは大変です。
エディタのフォーマッタやリンタ(例: black、ruff、flake8、isort)を導入すると、機械的にチェック・整形できます。
最初からツールに任せると早く身につきます。
Pythonの命名規則 PEP8
命名は可読性の核です。
まずはパッと見で役割がわかる名前を選び、次に「形」をそろえます。
次の表は、代表的な要素と推奨スタイルのまとめです。
要素 | スタイル | 例 |
---|---|---|
変数・関数 | スネークケース(snake_case) | total_count, get_user_name() |
クラス | パスカルケース(PascalCase) | UserAccount, HttpClient |
定数 | 全大文字 + アンダースコア | MAX_RETRY, DEFAULT_TIMEOUT |
モジュール・パッケージ | 小文字・短め・必要ならアンダースコア | utils, string_ops |
内部利用(非公開) | 先頭にアンダースコア | _internal_cache |
特殊メソッド | dunder(両端にダブルアンダースコア)予約のみ | __init__, __str__ |
変数と関数はスネークケース
OK/NG例
# NG
userName = "Alice" # キャメルケースは避ける
GetUserName = lambda u: u.name # 関数名は小文字で
# OK
user_name = "Alice"
def get_user_name(user): # 動詞から始めると意図が伝わる
return user.name
ポイント
読みやすさのため短すぎず長すぎずにします。
ブール値はis_
, has_
, can_
などを先頭につけると意図が明確です(例: is_active
)。
クラス名はパスカルケース
OK/NG例
# NG
class user_profile:
pass
# OK
class UserProfile:
pass
ポイント
抽象基底クラスなども同じパターンで名付けます(例: FileReader
, AbstractParser
)。
定数は全て大文字
OK/NG例
# NG
pi = 3.14159
# OK
PI = 3.14159
MAX_CONNECTIONS = 20
ポイント
- 定数はモジュールレベル(ファイル直下)に定義し、他の関数やクラスから参照します。
モジュール名とパッケージ名は小文字
OK/NG例
# NG
DataLoader.py
MyLib/
# OK
dataloader.py
mylib/
string_utils.py
ポイント
モジュール名は短く。必要ならアンダースコアで区切ります。
非公開は先頭にアンダースコア
OK/NG例
_internal_cache = {} # モジュール内部だけで使いたい
def _normalize(text): # 外に見せたくない関数
return " ".join(text.split())
class Tokenizer:
def __init__(self):
self._buffer = [] # クラス内部向け
ポイント
先頭にアンダースコアをつけても完全な隠蔽にはなりませんが、「内部用」の合図として機能します。
クラスの属性で先頭にダブルアンダースコア(例: __value
)を付けると名前マングリングが起きますが、やり過ぎるとテストや継承が難しくなるため慎重に使います。
特殊メソッド名は予約に従う
正しい使い方
class Point:
def __init__(self, x, y): # 生成時に呼ばれる
self.x = x
self.y = y
def __str__(self): # str(point) で使われる
return f"({self.x}, {self.y})"
def __eq__(self, other): # == 比較
return (self.x, self.y) == (other.x, other.y)
ポイント
__something__
という形式は予約語です。定義済みのプロトコル(__len__
, __iter__
, __enter__
, __exit__
など)だけに使い、独自のダンダーメソッド名は作りません。
インデントと空白のルール PEP8
見た目を整える最大の要素はインデントと空白です。
PEP8の原則に沿うと、視線の移動が小さくなり、差分も綺麗になります。
インデントはスペース4個
OK/NG例
# NG: 2スペースや不揃いは避ける
def add(x, y):
return x + y
# OK: 4スペース
def add(x, y):
return x + y
タブではなくスペースを使う
説明と例
Python 3ではタブとスペースの混在でIndentationErrorになることがあります。エディタ設定で「Tabキーでスペース4個を挿入」にします。
# NG: タブ混在の例 (見た目は同じでも崩れます)
def f():
<TAB>print("mixed") # 実際のタブは目に見えません
# OK: スペースのみ
def f():
print("spaces only")
演算子の前後は1スペース
OK/NG例
# NG
a=1+2*3
value = x*y
# OK
a = 1 + 2 * 3
value = x * y
# 例外: 単項演算子は詰める
b = -5
mask = ~flags
行継続時の位置
長い式を折り返すときは、行継続は演算子の前で改行するのが読みやすいです。
# OK: 演算子の前で改行
total = (price
+ tax
- discount)
カンマやコロンの前は空白なし
OK/NG例
# NG
if x == 1 : # コロンの前に空白を置かない
print("one")
items = [1 , 2 , 3] # カンマの前に空白を置かない
# OK
if x == 1:
print("one")
items = [1, 2, 3]
括弧の直前直後に空白を入れない
OK/NG例
# NG
spam( ham[ 1 ], { eggs: 2 } )
# OK
spam(ham[1], {eggs: 2})
キーワード引数の=は空白なし
OK/NG例
# NG
open(file = "data.txt", mode = "w")
# OK
open(file="data.txt", mode="w")
スライスの: の空白に注意
OK/NG例
# NG
text = "Hello, world"
head = text[ 0 : 5 ] # コロンの前後の空白は不要
step = text[0 : 10 : 2] # 同様に不要
# OK
text = "Hello, world"
head = text[0:5]
step = text[0:10:2]
# 多次元インデックスではカンマの後に1スペース
matrix = arr[1:9, 3:, ::2]
行の長さは79文字目安
コード行は79文字、コメントやdocstringは72文字を目安に折り返します。狭い画面でもレビューしやすくなるためです。
自動整形ツール(例: blackは88文字デフォルト)を使う場合、プロジェクトの合意に従います。
長い式は括弧内で折り返す
OK/NG例
# NG: バックスラッシュは脆い(コメントや空白で壊れやすい)
result = a + b + c + d + e + f + g + \
h + i
# OK: 括弧、ブラケット、ブレース内では暗黙の行継続が可能
result = (
a + b + c + d
+ e + f + g
+ h + i
)
# 辞書や引数も同様
config = {
"host": "localhost",
"port": 5432,
"user": "app",
}
行末の空白は残さない
無意味な差分を生むため削除します。エディタの「自動トリム」を有効にしましょう。
トップレベルは空行2行
OK/NG例
# OK: ファイル直下のクラスや関数は2行で区切る
PI = 3.14159
def area(r):
return PI * r * r
class Circle:
pass
クラス内メソッドは空行1行
OK/NG例
class Calculator:
def add(self, x, y):
return x + y
def sub(self, x, y): # メソッド間は1行空ける
return x - y
ファイル末尾は改行で終える
POSIXの約束事であり、diffが綺麗になります。多くのツールも最終行改行を前提とします。
importの書き方と順序 PEP8
importは「どこから何を使っているか」を伝える表紙です。
並び順と配置で読み手の負担を減らします。
importはファイル先頭に書く
原則として関数やクラスの外、ファイル先頭に配置します。循環依存や重い依存を避けるために遅延importする場合のみ例外とします。
# NG
def handle():
import json # 原則は先頭に
return json.loads("[]")
# OK
import json
def handle():
return json.loads("[]")
モジュールdocstringの後に置く
OK例
"""サンプルモジュール(PEP8準拠の構造例)。"""
import math
1行に1つのimport
OK/NG例
# NG
import os, sys # 並列表記は避ける
# OK
import os
import sys
絶対importを推奨
Python 3では暗黙の相対importが廃止されています。基本は絶対importを使います。
パッケージ内部で明示的相対import(from . import util)は妥当な場合もあります。
# 推奨: 絶対import
from collections import defaultdict
import myproject.utils.string_ops as string_ops
# 妥当なケース: 明示的相対import(パッケージ内部)
from . import util # 現在のパッケージから
from ..core import models # 1つ上のパッケージから
ワイルドカードimportを避ける
from module import * は名前空間を汚染し、静的解析や検索が効きにくくなります。必要なものだけを明示します。
# NG
from math import *
# OK
from math import sqrt, pi
標準ライブラリ サードパーティ 自作の順
並び順の例
"""importの順序と空行の例。"""
# 1. 標準ライブラリ
import os
from pathlib import Path
# 2. サードパーティ
import requests
# 3. 自作(ローカル)モジュール
from myapp.config import settings
from myapp.core.services import service
グループ間に空行を入れる
上記の3グループ間は1行空けて視覚的に分けます。同一グループ内はアルファベット順に並べるとさらに見やすくなります(isortで自動化可能)。
asの別名は必要時のみ
OK/NG例
# NG: 不要な別名は読みにくい
import numpy as n
# OK: 名前衝突や慣習的な短縮だけ
import numpy as np # 慣習的に広く使われる
from urllib.parse import urlparse as parse_url # 意図が伝わる
モジュール構造の完全例
以下は、docstring、import、定数、関数、エントリポイントの並びをPEP8に沿って示したサンプルです。
"""PEP8に沿ったモジュール構成のサンプル。"""
# 標準ライブラリ
from pathlib import Path
import sys
# サードパーティ
# (例示のみ。インストールされていない環境では使わない)
# import requests
# 自作
# from myapp.utils import read_text
PI = 3.14159 # 定数は全大文字
def area(r): # スネークケースの関数名
"""円の面積を返す。"""
return PI * (r ** 2)
class Circle: # パスカルケースのクラス名
def __init__(self, r):
self._r = r # 非公開属性は先頭にアンダースコア
def area(self):
return area(self._r)
def main(): # スクリプトのエントリポイント
c = Circle(2)
print(f"area = {c.area()}") # キーワード引数の=は空白なし
if __name__ == "__main__":
sys.exit(main())
area = 12.56636
まとめ
PEP8は「Pythonicな書き方」をチームで共有するための、読みやすさ第一の約束事です。
本記事では、命名(スネーク/パスカル/定数/非公開/特殊メソッド)、インデントと空白(4スペース、演算子や括弧の空白、行長、空行、末尾改行)、そしてimport(配置、1行1つ、順序、ワイルドカード回避、別名)の実践ポイントを具体例で整理しました。
最初は覚えることが多く感じられますが、エディタ設定と自動整形ツール(blackやruff、isortなど)を導入すれば、自然とPEP8準拠の形が身につきます。
迷ったら「より読みやすく、より一貫した形」を選ぶ、これがPEP8の精神です。