python-best-practices について
Python 3.11 以降のコードを書く、レビューする、リファクタリングする開発者向けのガイドです。影響度順の75ルールに適用しない条件も記載し、状況に応じた判断を支援します。
主な機能
- 018カテゴリにわたる75ルール
- 02影響度に基づく優先順位
- 03Python 3.11以降を前提
- 04ルールを適用しない条件の提示
活用シーン
- 01Pythonコードの正確性レビュー
- 02新規Pythonモジュールへの指針適用
- 03変更中のコードのリファクタリング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nathan-gage/ python-skills --skill python-best-practicesインストール後、Claude Code で/python-best-practicesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
AGENTS.mdmetadata.jsonREADME.mdrules/_sections.md_template.mdapi-deprecated-aliases.mdapi-immutable-transforms.mdapi-instance-vs-module-fn.mdapi-keyword-only-params.mdapi-model-cohesion.mdapi-no-boolean-flag-params.mdapi-no-private-access.mdapi-required-before-optional.mdapi-underscore-for-private.mddata-aware-datetimes.mddata-delete-dead-variants.mddata-derive-dont-store.mddata-discriminated-unions.mddata-encapsulate-mutable-state.mddata-explicit-variants.mddata-mutable-defaults.mddata-mutation-contract.mddata-newtype-for-ids.mddata-phased-composition.mddata-reject-bool-as-int.mddata-sentinel-when-none-is-valid.mderror-assert-debug-only.mderror-assert-never-exhaustiveness.mderror-consolidate-try-except.mderror-context-managers.md詳細
Python のベストプラクティス
Python の記述とレビューのガイドラインです。影響度に応じて優先順位を付けた、8 つのカテゴリにわたる 75 のルールをまとめています。
ルールへの該当はシグナルであり、最終的な判断ではありません。ほとんどのルールは新しいコードに対する設計上の好みであり、リポジトリ全体で修正すべきバグではありません。レビューで指摘したり、安定したコードをリファクタリングしたりする前に、ルールの影響度を確認してください。
クイックリファレンスの項目はきっかけであり、適用してよいという許可ではありません。レビューの指摘や変換にルールを適用する前に、ルールファイルを開き、反対のシグナルを確認してください。ここでいう反対のシグナルとは、適用すべきでない状況を示す、マーカーで始まる段落(**When ...**/**Scope:**/**Preserve ...**)です。
適用する場面
- 新しい Python モジュール、関数、クラス、データモデルを記述するとき
- 正確性や型安全性についてコードをレビューするとき
- 変更中のコードに含まれるパターンをリファクタリングするとき
安定したコード全体にこれらのルールを一律に適用するのは避けてください。大抵の場合、変更に伴うコストに見合うメリットはありません。
影響度
CRITICAL— 実際に発生し得るバグの種類(データ破損、キャンセルの握りつぶし、安全でないデフォルト設定など)を防ぎます。見つけたら修正してください。HIGH— 正確性や保守性を大きく向上させます。ほとんどの状況で修正する価値があります。MEDIUM— 優れたプラクティスであり、明確さの向上や逸脱の防止につながります。新しいコードには適用し、安定したコードに不要な変更を加えないでください。LOW-MEDIUM/LOW— スタイルや小規模な最適化に関するものです。機会があれば適用してください。
Python のバージョンの基準
ルールは Python 3.11 以降を前提としています。より新しいバージョンに依存するルールには、その旨がインラインで記載されています。
warnings.deprecated()— 3.13 以降zoneinfo— 3.9 以降isinstance()のユニオン型 — 3.10 以降assert_never— 3.11 以降(typing_extensionsでバックポート可能)- PEP 695 の
type文とジェネリック構文 — 3.12 以降(types-modern-syntaxにインラインで記載)
applicability:pydantic のタグが付いたルールは、Pydantic 固有です。
優先度別のルールカテゴリ
| 優先度 | カテゴリ | 影響度 | プレフィックス |
|---|---|---|---|
| 1 | データモデリング | HIGH | data- |
| 2 | エラー処理 | MEDIUM-HIGH | error- |
| 3 | 型安全性 | MEDIUM-HIGH | types- |
| 4 | API 設計 | MEDIUM | api- |
| 5 | コードの簡素化 | LOW-MEDIUM | simplify- |
| 6 | パフォーマンス | LOW-MEDIUM | perf- |
| 7 | 命名 | LOW-MEDIUM | naming- |
| 8 | インポートと構造 | LOW | imports- |
セクションに付けられた影響度は、一般的なケースを示すラベルです。個々のルールの影響度は、その前後 1 段階の範囲に及びます。ルールファイルを確認してください。
クイックリファレンス
データモデリング(data-)
data-mutable-defaults—def f(items=[])のような定義は避けてください。Noneと関数本体での構築、またはdefault_factoryを使用してくださいdata-derive-dont-store— 状態から真偽値を計算してください。互いに対応するフラグをキャッシュしないでくださいdata-mutation-contract— 関数ごとに曖昧さのない契約を 1 つ定めてください。変更する(新しい情報を返すのは問題ありません)か、新しい値を返すかのどちらかにし、変更済みのオブジェクトを新しい値のように返さないでくださいdata-aware-datetimes— タイムゾーン対応のdatetime.now(timezone.utc)を使用してください。utcnow()は非推奨ですdata-discriminated-unions— オプショナルフィールドの寄せ集めではなく、バリアントにタグを付けてくださいdata-explicit-variants—is_thread/is_editフラグより、モードごとの具体的なクラスを使用してくださいdata-phased-composition— 同時に存在するオプショナル項目は、1 つのネストしたオプショナル項目にまとめてくださいdata-encapsulate-mutable-state— 変更可能な状態を、明確さを保てる最小のスコープに閉じ込めてくださいdata-sentinel-when-none-is-valid—Noneが意味のある値である場合は、非公開のセンチネルを使用してくださいdata-newtype-for-ids—NewType('UserId', str)を使用し、ID 同士を混同できないようにしてくださいdata-delete-dead-variants— 生成されないユニオンのバリアントは削除してくださいdata-reject-bool-as-int—boolはintのサブクラスです。数値チェックの前に明示的に拒否してください
エラー処理(error-)
error-specific-exceptions— 具体的な型を捕捉します。裸のexcept:やexcept BaseException:は使わないでください(Ctrl-C や非同期キャンセルを妨げます)。except Exception:は 3.8 以降ではキャンセルセーフですerror-context-managers— ファイル、ロック、セッションにはwith/async withを使いますerror-assert-debug-only—assertは-Oで取り除かれるため、実行時の契約には使わないでくださいerror-validate-at-boundaries— 高コストな処理を始める前に、システム境界で速やかに失敗させますerror-trust-validated-state— 不変で、ローカルに構築された状態を信頼しますerror-consolidate-try-except— 捕捉と処理が同じブロックは統合しますerror-assert-never-exhaustiveness— 網羅性の確認にはtyping.assert_neverを使いますerror-raise-from-for-chains— 因果関係を保つため、raise NewErr(...) from originalを使いますerror-inherit-base-exceptions— 互換性のため、新しい例外は既存の基底クラスを継承しますerror-log-exception-context—except内ではlogger.exception(...)を使い、ログにトレースバックを残しますerror-repr-in-messages— エラーテキスト内の識別子にはf"tool {name!r}"を使いますerror-match-types-not-messages— メッセージの部分文字列ではなく、例外の型とステータスコードで分類します
型安全性(types-)
types-fix-errors-not-ignore— 型エラーを修正します。# type: ignoreは最後の手段ですtypes-avoid-any—Anyよりも Protocol、TypeVar、ユニオンを使いますtypes-typeddict-over-dict-any— 構造が既知の場合はTypedDict/ dataclass を使いますtypes-literal-for-fixed-sets— 固定文字列にはLiteral["a", "b"]を使いますtypes-fix-types-not-cast— 定義を修正します。cast()は実行時に本当に型が絞り込まれる場合にのみ使いますtypes-isinstance-for-narrowing— 絞り込みにはhasattr/type(x).__name__よりisinstance()を使いますtypes-narrow-to-runtime-reality— アノテーションを、制御フローで実際に許容される値に合わせますtypes-trust-the-checker— 型チェッカーがすでに保証する実行時チェックは削除しますtypes-remove-redundant-optional— 値が必ず存在する場合は| Noneを削除しますtypes-type-checking-imports— 任意または重いインポートにはif TYPE_CHECKING:を使いますtypes-modern-syntax—Optional/Union/typing.Listではなく、X | None、list[str]を使いますtypes-sequence-over-list-params— 読み取り専用の引数にはSequence/Mappingを使います。listは不変です
API 設計(api-)
api-required-before-optional— 必須フィールドを任意フィールドより前に置きます(Python ではこの順序が強制されます)api-keyword-only-params— 任意の引数や設定用の引数には*マーカーを使いますapi-no-boolean-flag-params—True, Falseの羅列よりLiteral/Enumを使いますapi-immutable-transforms— 入力を変更せず、新しいコレクションを返しますapi-model-cohesion— モデルはフラットに保ち、重複するフィールドや単一キーでラップされたフィールドを避けますapi-underscore-for-private— 内部用には_prefixを使い、__all__から除外しますapi-deprecated-aliases— API 名を変更する場合はwarnings.deprecated()(3.13 以降)を使いますapi-no-private-access— モジュールの外部から_prefixed名にアクセスしないでくださいapi-instance-vs-module-fn— 所有関係に合った名前空間を選びます
コードの簡素化(simplify-)
simplify-early-return— 早期に return し、正常系を入れ子にしないでくださいsimplify-extract-after-duplication— 2 回目の重複が判断の分岐点で、3 回目は抽出するのが安全な既定値ですsimplify-cached-property— 不変インスタンスには@cached_propertyを使います。スレッドセーフではありませんsimplify-comprehensions—for+.append()より内包表記を使いますsimplify-any-all-builtins— 手動のフラグ設定とbreakよりany()/all()を使いますsimplify-fallback-or— 偽値に意味上の違いがない場合はx or defaultを使いますsimplify-flatten-nested-if— 間にコードがなければif cond1 and cond2:を使いますsimplify-inline-single-use-vars— 1 回しか使わない中間変数を削除しますsimplify-remove-dead-code— コメントアウトされたコードは削除します。履歴は git に保存されています
パフォーマンス(perf-)
perf-set-for-membership—inによるチェックを繰り返す場合はsetを使いますperf-dict-index-over-nested-loops— 検索用にdictを構築しますperf-lru-cache-pure-fns— 純粋関数にはfunctools.lru_cache/functools.cacheを使いますperf-generator-over-list— メモリやレイテンシが重要な場合は、ジェネレーターでストリーミングしますperf-combine-iterations—filterとmapを1回の処理にまとめますperf-compile-regex-module-level— 静的な正規表現はモジュールスコープでコンパイルします。タイトなループで効果がありますperf-type-adapter-constant— モジュールスコープのTypeAdapter(適用対象:pydantic)perf-isinstance-tuple-syntax— タプル形式はわずかに高速です。プロファイリングで判明したホットパスでのみ使用します
命名(naming-)
naming-rename-on-behavior-change— 動作が変わったら名前を変更します。古い名前は誤解を招きますnaming-consistent-terminology— 同じ概念には、コード/ドキュメント/エラーで同じ言葉を使いますnaming-specific-over-generic—toolset_idを使い、単なるidは避けますnaming-drop-redundant-prefixes—ToolConfig.descriptionを使い、ToolConfig.tool_descriptionは避けますnaming-upper-case-constants— 定数にはMAX_RETRIESを使い、内部用には_を接頭辞として付けますnaming-no-type-suffixes—_dict/_listのような接尾辞は付けません。型は型アノテーションで示します
インポートと構成(imports-)
imports-no-side-effects— モジュールはインポート時に低コストでなければなりません。インポート時にネットワーク/モデル/環境変数を読み込まないでくださいimports-top-of-file— インポートはファイルの先頭に記述します。循環/オプション/遅延インポートの例外は文書化しますimports-optional-dependencies— インストール方法のヒントを添えてtry/except ImportErrorを使いますimports-scope-helpers-to-usage— ヘルパーは使用箇所の近くに定義しますimports-remove-unused— 未使用のインポートを削除しますimports-no-duplicates— 同じ名前を複数回インポートしませんimports-lightweight-init— 親の__init__.pyはサブモジュールのインポートごとに実行されます。重い依存関係やオプションの依存関係を含めないでください
使い方
詳細は各ルールファイルを参照してください。
rules/data-mutable-defaults.md
rules/error-specific-exceptions.md
各ルールには次の内容が含まれます。
- フロントマターに記載された影響レベル
- 簡単な説明
- 誤った例
- 正しい例
- エッジケースに関する任意の注記
すべてのルールを展開した完全版のガイドについては、AGENTS.md を参照してください。