Python:PEP 8とコーディング規則
Pythonコードを読みやすく、一貫した形式で記述するための基本規則をまとめた資料です。
Python 3.11以降を想定しています。
目次
- PEP 8とは
- コーディング規則が必要な理由
- 命名形式の読み方
- 基本的な命名規則
- インデント・行の長さ・空行
-
importの書き方 - 空白・改行・式の書き方
- コメントとドックストリング
- 推奨される比較・条件式
- 実行できる良い例
- よくある修正例
- 自動チェック・自動整形
- まとめ
1. PEP 8とは
**PEP 8(ペップ・エイト)**は、Pythonコードのスタイルガイドです。
- PEP:Python Enhancement Proposal(パイソン・エンハンスメント・プロポーザル)
- 8:提案番号
PEP 8では、主に次を定めています。
- 命名方法
- インデント
- 行の長さ
- 空行
-
importの並べ方 - 空白の使い方
- コメント
- 読みやすい条件式
PEP 8の目的
コードは書く回数より、読まれる回数の方が多いため、読みやすさと一貫性を重視する。
絶対に機械的に守る規則なのか
PEP 8は重要な基準ですが、次の優先順位で判断します。
1. 案件・会社・チームの規約
2. 既存プロジェクトの一貫性
3. 使用フレームワークやツールの規約
4. PEP 8
既存コードとの一貫性を壊してまで、1行だけ形式を変えると読みづらくなる場合があります。
一言
PEP 8はPythonコードの読みやすさと統一感を高めるスタイルガイドで、命名・インデント・空白・行長などの基本方針を定めています。
2. コーディング規則が必要な理由
2-1. 読む人が迷いにくい
# 何を表すか分かりにくい
x = 1200
# 目的が分かりやすい
total_price = 1200
2-2. 名前から種類や役割を推測できる
class OrderService:
pass
MAX_RETRY_COUNT = 3
def calculate_total() -> int:
return 0
| 名前 | 推測できること |
|---|---|
OrderService |
クラス |
MAX_RETRY_COUNT |
定数 |
calculate_total |
関数・メソッド |
2-3. レビューしやすい
書き方の違いではなく、処理内容に集中できます。
2-4. 自動ツールを利用しやすい
RuffなどのLint・整形ツールで、一定の規則を自動確認できます。
3. 命名形式の読み方
| 形式 | 読み方 | 例 | 特徴 |
|---|---|---|---|
snake_case |
スネークケース | total_price |
小文字を_で区切る |
UPPER_SNAKE_CASE |
アッパー・スネークケース | MAX_RETRY_COUNT |
大文字を_で区切る |
CapWords |
キャップワーズ | OrderService |
各単語の先頭を大文字にする |
PascalCase |
パスカルケース | OrderService |
PEP 8のCapWordsとほぼ同じ意味で使われる |
camelCase |
キャメルケース | totalPrice |
先頭は小文字、以後の単語を大文字にする |
_leading_underscore |
先頭アンダースコア | _internal_value |
内部用であることを示す慣習 |
__dunder__ |
ダンダー | __init__ |
Pythonが予約する特殊名 |
Pythonでは、クラスは
CapWords、関数・変数はsnake_case、定数はUPPER_SNAKE_CASEが基本です。
4. 基本的な命名規則
まず覚える基本8分類
| 番号 | 対象 | 規則 | 良い例 | 避けたい例 |
|---|---|---|---|---|
| 1 | モジュール | 短い小文字。必要なら_
|
order_service.py |
OrderService.py |
| 2 | パッケージ | 短い小文字。_はできるだけ避ける |
orders |
Order_Package |
| 3 | クラス | CapWords |
OrderService |
order_service |
| 4 | 例外クラス |
CapWords。エラーならErrorを末尾に付ける |
OrderNotFoundError |
order_not_found |
| 5 | 関数・メソッド | snake_case |
calculate_total |
calculateTotal |
| 6 | 変数・引数 | snake_case |
item_count |
ItemCount |
| 7 | 定数 | UPPER_SNAKE_CASE |
MAX_RETRY_COUNT |
maxRetryCount |
| 8 | 型変数 | 短いCapWordsまたは意味のある名前 |
T、KeyT
|
type_variable |
4-1. モジュール名
良い例
pricing.py
order_service.py
file_utils.py
避けたい例
Pricing.py
order-Service.py
file utils.py
理由:
-
import名として扱いやすい - OS間の大文字・小文字差による問題を減らす
- Pythonの一般的な命名と揃う
4-2. パッケージ名
orders/
users/
shoptools/
PEP 8では、短い小文字を推奨し、アンダースコアは非推奨寄りです。ただし、実際のプロジェクトでは可読性や既存規約によりshop_toolsのような名前も使われます。
4-3. クラス名
class OrderService:
pass
class ShippingAddress:
pass
4-4. 例外クラス名
class OrderNotFoundError(Exception):
"""注文が見つからない場合の例外。"""
エラーを表す例外では、末尾にErrorを付けると役割が明確です。
4-5. 関数・メソッド名
def calculate_total(price: int, quantity: int) -> int:
return price * quantity
動作を表すため、動詞から始める名前がよく使われます。
calculate_total
find_user
create_order
validate_input
4-6. 変数・引数名
unit_price = 200
item_count = 3
1文字名は、短いループや数式など範囲が限定される場合を除き、目的が分かる名前を使います。
# 範囲が短く意味が明確なら許容されやすい
for i in range(3):
print(i)
4-7. 定数名
Pythonに言語として変更不能な定数はありませんが、変更しない値を大文字で表します。
TAX_RATE = 0.10
MAX_RETRY_COUNT = 3
DEFAULT_TIMEOUT_SECONDS = 30
4-8. 型変数名
from typing import TypeVar
T = TypeVar("T")
KeyT = TypeVar("KeyT")
ValueT = TypeVar("ValueT")
補足:selfとcls
class User:
user_count = 0
def __init__(self, name: str) -> None:
self.name = name
@classmethod
def get_user_count(cls) -> int:
return cls.user_count
| 用途 | 第1引数 |
|---|---|
| インスタンスメソッド | self |
| クラスメソッド | cls |
補足:内部用の名前
def _normalize_text(value: str) -> str:
return value.strip().lower()
先頭_は「外部公開を意図しない内部用」という慣習です。アクセスを物理的に禁止するものではありません。
補足:名前マングリング
class Account:
def __init__(self) -> None:
self.__token = "sample-token"
先頭に__を付けると、継承時の名前衝突を減らすために名前マングリングが行われます。単なるprivateの代替ではありません。
補足:キーワードとの衝突
class_ = "sample"
Pythonのキーワードと衝突する場合は、末尾に_を付けます。
補足:ダンダー名
__init__
__str__
__len__
__name__のようなダンダー名はPythonが特別な用途に予約しています。独自のダンダー名を新しく作らないようにします。
5. インデント・行の長さ・空行
5-1. インデントはスペース4つ
def calculate_total(price: int, quantity: int) -> int:
subtotal = price * quantity
return subtotal
- タブとスペースを混在させない
- 継続行は見やすく揃える
total = calculate_total(
price=200,
quantity=3,
)
5-2. 行の長さ
PEP 8の基本:
| 対象 | 推奨上限 |
|---|---|
| コード | 79文字 |
| コメント・ドックストリング | 72文字 |
ただし、BlackやRuff Formatterなど、88文字を標準とするツールもあります。案件設定を優先します。
5-3. トップレベル定義の間は空行2行
DEFAULT_PRICE = 200
def calculate_total(price: int, quantity: int) -> int:
return price * quantity
class Order:
pass
5-4. クラス内のメソッド間は空行1行
class Order:
def __init__(self, total: int) -> None:
self.total = total
def is_free_shipping(self) -> bool:
return self.total >= 3000
5-5. 演算子で改行する場合
読みやすい例:
total_price = (
item_price
+ shipping_fee
+ handling_fee
- discount
)
演算子を次の行の先頭に置くと、各項の関係を読み取りやすくなります。
6. importの書き方
6-1. ファイル先頭にまとめる
from __future__ import annotations
import json
from pathlib import Path
import requests
from shop_tools.pricing import calculate_total
6-2. グループを空行で分ける
1. 標準ライブラリ
2. 外部ライブラリ
3. 自作・ローカルパッケージ
6-3. 原則1行1モジュール
# 推奨
import os
import sys
# 避ける
import os, sys
from形式では、同じモジュールから複数名を読み込めます。
from pathlib import Path, PurePath
6-4. ワイルドカードを避ける
# 名前の出所が分かりにくくなる
from sample_module import *
推奨:
from sample_module import calculate_total
6-5. 標準的な別名
import numpy as np
import pandas as pd
プロジェクトやライブラリで広く定着している別名を使います。独自で分かりにくい略称を増やさないようにします。
7. 空白・改行・式の書き方
7-1. 演算子の前後に空白
subtotal = price * quantity
total = subtotal + tax
is_valid = total >= 0
7-2. カンマの後に空白
items = ["apple", "banana", "orange"]
7-3. 括弧の内側に不要な空白を入れない
# 推奨
print(calculate_total(200, 3))
# 避ける
print( calculate_total( 200, 3 ) )
7-4. 添字・スライス
items[0]
items[1:3]
7-5. キーワード引数の=周辺
# キーワード引数では空白を入れない
total = calculate_total(price=200, quantity=3)
型注釈とデフォルト値を併用する場合:
def calculate_tax(subtotal: int, tax_rate: float = 0.10) -> int:
return int(subtotal * tax_rate)
7-6. 複合文を1行へ詰め込まない
# 避ける
a = 1; b = 2
# 推奨
a = 1
b = 2
# 避ける
if is_valid: process()
# 推奨
if is_valid:
process()
7-7. 末尾カンマ
複数行のリストや引数では末尾カンマを付けると、差分が見やすくなります。
items = [
"apple",
"banana",
"orange",
]
8. コメントとドックストリング
コメント
「何をしているか」をコードが表し、「なぜそうするか」をコメントで補います。
# 外部APIの仕様上、金額は整数へ切り捨てて送信する。
tax = int(subtotal * tax_rate)
避けたい例:
# subtotalにtaxを足す
total = subtotal + tax
コードと同じ内容を繰り返しているだけです。
インラインコメント
retry_count = 3 # 外部サービスの運用上限
- 文から十分な空白を取る
- 多用しない
- 古くなったコメントを残さない
ドックストリング
def calculate_total(price: int, quantity: int) -> int:
"""単価と数量から合計金額を返す。"""
return price * quantity
ドックストリングは、モジュール・クラス・関数などの公開仕様を説明します。詳しい規則はPEP 257で扱われます。
9. 推奨される比較・条件式
9-1. Noneはisで比較
if result is None:
print("結果なし")
if result is not None:
print("結果あり")
避ける:
if result == None:
pass
9-2. 真偽値を冗長に比較しない
# 推奨
if is_active:
print("有効")
# 避ける
if is_active == True:
print("有効")
9-3. 空のコレクションは真偽値で判定
items: list[str] = []
if not items:
print("商品なし")
9-4. 型判定はisinstance()
if isinstance(value, int):
print("整数")
避けることが多い例:
if type(value) is int:
pass
isinstance()は継承関係も考慮します。
9-5. 例外を広く捕まえすぎない
try:
number = int("100")
except ValueError as error:
print(f"変換失敗: {error}")
避ける:
try:
number = int("100")
except Exception:
pass
10. 実行できる良い例
pep8_sample.py:
from __future__ import annotations
from dataclasses import dataclass
TAX_RATE = 0.10
FREE_SHIPPING_THRESHOLD = 3_000
@dataclass(frozen=True)
class OrderItem:
"""注文商品を表す。"""
name: str
unit_price: int
quantity: int
def subtotal(self) -> int:
"""商品の小計を返す。"""
return self.unit_price * self.quantity
def calculate_order_total(items: list[OrderItem]) -> tuple[int, int, int]:
"""注文商品の小計・税額・合計を返す。"""
subtotal = sum(item.subtotal() for item in items)
tax = int(subtotal * TAX_RATE)
total = subtotal + tax
return subtotal, tax, total
def main() -> None:
"""サンプル注文の計算結果を表示する。"""
items = [
OrderItem(name="Sample A", unit_price=200, quantity=2),
OrderItem(name="Sample B", unit_price=200, quantity=1),
]
subtotal, tax, total = calculate_order_total(items)
shipping_label = (
"送料無料"
if total >= FREE_SHIPPING_THRESHOLD
else "送料別"
)
print(f"小計: {subtotal}")
print(f"税額: {tax}")
print(f"合計: {total}")
print(f"配送: {shipping_label}")
if __name__ == "__main__":
main()
実行:
python pep8_sample.py
実行結果:
小計: 600
税額: 60
合計: 660
配送: 送料別
この例で確認できる規則:
- モジュール名:
pep8_sample.py - クラス名:
OrderItem - 関数・メソッド名:
calculate_order_total、subtotal - 変数名:
shipping_label - 定数名:
TAX_RATE - インデント:スペース4つ
- トップレベル定義間:空行2行
- 複数行要素:末尾カンマ
-
main()による実行入口の分離
11. よくある修正例
命名
# 修正前
def CalculateTotal(ItemPrice, ItemCount):
return ItemPrice * ItemCount
# 修正後
def calculate_total(item_price: int, item_count: int) -> int:
return item_price * item_count
長い行
# 修正前
message = create_message(user_name, order_number, ordered_at, payment_method, shipping_address)
# 修正後
message = create_message(
user_name,
order_number,
ordered_at,
payment_method,
shipping_address,
)
空白
# 修正前
total=price*quantity+tax
# 修正後
total = price * quantity + tax
複雑な条件
# 修正前
if user is not None and user.is_active and user.age >= 18 and not user.is_blocked:
process_user(user)
# 修正後
is_available_user = (
user is not None
and user.is_active
and user.age >= 18
and not user.is_blocked
)
if is_available_user:
process_user(user)
マジックナンバー
# 修正前
if retry_count >= 3:
stop_processing()
# 修正後
MAX_RETRY_COUNT = 3
if retry_count >= MAX_RETRY_COUNT:
stop_processing()
12. 自動チェック・自動整形
RuffでLint
python -m pip install ruff
ruff check .
自動修正可能な項目を修正:
ruff check . --fix
Ruff Formatterで整形
ruff format .
設定例
pyproject.toml:
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP"]
| ルール群 | 主な内容 |
|---|---|
E |
pycodestyleのエラー系 |
F |
Pyflakes系の誤り |
I |
import並び替え |
N |
命名規則 |
UP |
新しいPython構文への更新提案 |
自動整形ツールの設定がPEP 8の79文字と異なる場合があります。プロジェクト設定を正として、全員で揃えます。
13. まとめ
全体まとめ
PEP 8はPythonの代表的なコーディングスタイルガイドです。基本的には、モジュール・関数・変数を
snake_case、クラスをCapWords、定数をUPPER_SNAKE_CASEで書きます。インデントはスペース4つ、コードの行長は原則79文字、トップレベルの関数やクラス間は空行2行です。また、importは標準・外部・自作の順で分け、Noneはisで比較します。実務ではPEP 8を基準にしつつ、チームと既存プロジェクトの規約を優先します。
命名の最小セット
module_name.py モジュール
package_name パッケージ
ClassName クラス
CustomError 例外
function_name 関数・メソッド
variable_name 変数・引数
CONSTANT_NAME 定数
_internal_name 内部用
最低限の確認
ruff check .
ruff format --check .