Pythonプロジェクトの未使用コードを一掃!vultureで始めるコード整理術

Pythonプロジェクトの未使用コードを一掃!vultureで始めるコード整理術

2025.08.31

こんにちは。サービス開発室の武田です。

いつの間にか使われなくなっていた関数ってありますよね。長期間運用しているプロジェクトやAIコーディングを繰り返していると、いつの間にか使われなくなったコードが蓄積されがちです。

先日、vultureという静的解析ツールを使ったところ、多くの未使用コードが見つかりました。

今回は、この体験をもとにvultureの効果的な活用方法を紹介します。

vultureとは?

vultureは、Pythonコードから未使用の関数、クラス、変数、インポートを検出してくれる静的解析ツールです。

主な特徴は次のとおりです。

  • インストールしてコマンド一発で手軽に使える
  • AST(抽象構文木)解析で未使用コードを高精度に発見
  • 結果に「60% confidence」などの信頼度が付くので判断しやすい
  • GitHub Actionsなどに簡単に組み込める

インストールも簡単です。

uv add vulture --dev

やってみた

基本的な使い方

まずは基本的な使い方から。コマンドはシンプルです。

# プロジェクト全体をチェック
uv run vulture src/

# 信頼度60%以上のもののみ表示(推奨)
uv run vulture src/ --min-confidence 60

# 結果をサイズ順でソート(大きなコードから順に表示)
uv run vulture src/ --min-confidence 60 --sort-by-size

実際に実行してみると、こんな感じで出力されました。

src/utils/helpers.py:10: unused variable 'client' (60% confidence)
src/api/endpoints.py:68: unused function 'format_response' (60% confidence)
src/handlers/base.py:214: unused method 'process_data' (60% confidence)

信頼度についての理解

vultureの便利な機能の1つが 信頼度(Confidence) です。「そのコードが本当に未使用である可能性」を数値で表したものです。

  • 100%: 関数・メソッド・クラスの引数、到達不可能なコード(確実に削除可能)
  • 90%: インポート文(ほぼ削除可能)
  • 60%: 属性、クラス、関数、メソッド、プロパティ、変数(要確認)

実際の運用では、次のような使い分けが推奨されています。

# CI/CDでエラーにしたい場合(高い信頼度のみ)
uv run vulture src/ --min-confidence 80

# 手動レビューで幅広くチェックしたい場合
uv run vulture src/ --min-confidence 60

検出結果をどう判断するか

実際に未使用コードが検出されたとき、すべてを機械的に削除するわけにはいきません。分類して慎重に判断する必要があります。

1. 安全に削除できるもの

# 明らかに不要なもの
import unused_module  # どこでも使われていない
client = create_client()  # 作ったけど使ってない

def orphan_function():  # どこからも呼ばれない
    return "Never called"

2. 偽陽性の可能性があるものは注意が必要

# 動的ディスパッチで呼ばれるメソッド
class Handler:
    def process_phase_start(self):  # 実際は動的に呼び出される
        pass

# 実際の呼び出し
method_name = f"process_phase_{phase}"
getattr(handler, method_name)()

# TypeDictのフィールド
class ConfigType(TypedDict):
    enabled: bool  # 型定義として必要
    timeout: int

3. YAGNI原則で思い切って削除

# 「将来使う予定」は削除対象
FUTURE_FEATURE = "not_implemented"

実際のプロジェクトでは、この分類で約8割が安全に削除できました。

ホワイトリストとignore機能で偽陽性を回避

動的ディスパッチやTypeDict周りでどうしても偽陽性が出てしまう場合があります。そんなときに便利なのがホワイトリストとignore_names機能です。

ホワイトリストの作り方

vultureのホワイトリストは、実行可能なPythonコードとして作成します。該当するコードを明示的に参照することで、「使用されている」と認識させるわけですね。

# vulture_whitelist.py
import mymodule.handlers as handlers
import mymodule.types as types

# TypeDictフィールドを明示的に参照
types.ConfigType.enabled  # type: ignore
types.ConfigType.timeout  # type: ignore

# Enum値を参照
handlers.Status.PENDING
handlers.Status.COMPLETED

# 動的ディスパッチメソッドを参照
handlers.Handler.process_phase_start  # type: ignore
handlers.Handler.process_phase_end  # type: ignore

実行方法

# ホワイトリストを含めて実行
uv run vulture src/ vulture_whitelist.py --min-confidence 60

# PYTHONPATHが必要な場合
PYTHONPATH=src uv run vulture src/ vulture_whitelist.py --min-confidence 60

実装時の注意点 です(最初よくわからずハマりました)。

  • ホワイトリストは 実行可能 なPythonコードである必要がある
  • インポートパスが解決できるよう、必要に応じてPYTHONPATHを設定
  • # type: ignoreでmypyの警告を抑制しておくとよいでしょう

ignore_namesで指定

--ignore-namesというオプションがサポートされており、ワイルドカードで無視するパターンを指定できます。

uv run vulture src/ --min-confidence 60 --ignore-names "process_phase_*

設定ファイルで運用を楽にする

毎回コマンドラインオプションを指定するのは面倒ですので、pyproject.tomlで設定を管理するのがお勧めです。

[tool.vulture]
min_confidence = 60
sort_by_size = true
paths = ["src/", "vulture_whitelist.py"]

ignore_names = [
    "process_phase_*",      # 動的呼び出しメソッド
    "_private_*",          # プライベートメソッド
]

exclude = [
    "tests/",
    "*/conftest.py",
    "*/__init__.py",
]

設定ファイルがあれば、コマンドもシンプルになります。

uv run vulture

毎回同じ設定で実行できるのでとても便利ですね。

実際の削除戦略と効果

段階的に進めるのがコツ

一気にすべてを削除するのではなく、段階的に進めるのが安全です。コードを削除した結果、動かなくなってしまってはどうしようもありません。安全に進めるためにはテストコードが必要不可欠です。そのためテストがない場合には、先にテストを書くことも必要でしょう。

# 明らかな未使用importから開始
uv run vulture src/ --min-confidence 90 | grep "unused import"

# 次に未使用変数
uv run vulture src/ --min-confidence 60 | grep "unused variable"

# 必ず各段階でテスト実行
uv run pytest && uv run ruff check

まとめ

vultureを効果的に活用するポイントをまとめておきます。

  1. 設定ファイル化: pyproject.tomlで設定を一元管理
  2. ホワイトリスト活用: 偽陽性を適切に除外
  3. 段階的削除: 安全なものから順次削除
  4. 継続的監視: CI/CDやhookなどを使いデッドコードの蓄積を防ぐ
  5. YAGNI原則の徹底: 「将来必要」より「現在必要」で判断

vultureは単なる削除ツールではなく、 コードベースの健康状態を可視化 してくれる診断ツールです。今回のプロジェクトではたくさんのデッドコードを発見・削除でき、コードの保守性が大幅に向上しました。

Pythonプロジェクトの「健康診断」として、ぜひ一度お試しください!

この記事をシェアする

facebookのロゴhatenaのロゴtwitterのロゴ

© Classmethod, Inc. All rights reserved.