01. 制御構文・関数・型ヒント
テーマ: 部門別KPI(達成率)の評価
学習点: f文字列, 型ヒント, match文(Python 3.10+), enumerate, 内包表記
依存: 標準ライブラリのみ / 難易度: 基礎
実行方法
uv run 01_kpi_match.py
スクリプト冒頭の PEP 723 メタデータ(# /// script)により、必要なライブラリは
uv が自動的に仮想環境へ導入します。事前の pip install は不要です。
解説
何をするプログラムか
企業では期初に部門ごとの目標(KPI: 重要業績評価指標)を設定し、期末に実績と突き合わせて評価します。このスクリプトは 5 つの部門について「実績 ÷ 目標」で達成率を計算し、達成率に応じて S〜D の 5 段階評価を付け、整形された一覧表として表示します。
さらに、目標を達成した部門の抽出(達成部門数)と、全部門の実績合計を目標合計で割った「全社達成率」も算出します。個々の部門を見るだけでなく全社を俯瞰する視点は、経営ダッシュボードの基本的な考え方です。30 本のシリーズの第 1 作として、Python の制御構文・関数・文字列整形の基礎をひととおり体験できる構成になっています。
コードの読みどころ
grade(rate: float) -> strには型ヒントが付いています。実行時の動作は変わりませんが、「float を受け取り str を返す」という仕様がコードだけで読み取れます。- 評価の分岐には Python 3.10 で導入された match 文を使い、
case r if r >= 1.20:のようにガード条件付きパターンで 5 段階を上から順に判定します。if-elif の連鎖より分岐の構造が見やすくなります。 for i, (name, actual, target) in enumerate(data, start=1):は、enumerate で連番を得ながらタプルを 3 変数にアンパックする定型パターンです。- 表の整形は f 文字列の書式指定で行います。
{name:<8}は左寄せ 8 桁、{rate:>8.1%}は右寄せでパーセント表示(0.98 →98.0%)と、揃った表が print だけで作れます。 achieved = [d[0] for d in data if d[1] >= d[2]]はリスト内包表記で「実績が目標以上の部門名」だけを 1 行で抽出しています。最終行のsum(d[1] for d in data)はジェネレータ式で、リストを作らずに合計しています。
実行結果の見方
表の各行で達成率と評価の対応を確認してください。営業一課は 132.0% で S、保守運用は 101.0% で A、営業二課は 98.0% なので「僅差で未達」の B と、match 文の境界値どおりに分類されています。
最終 2 行に注目すると、達成部門は 2/5 にとどまる一方、全社達成率は 88.5% です。営業一課の大幅超過が他部門の未達をかなり補っており、「部門別の達成状況」と「全社合計」は別の情報を与えることが読み取れます。
ソースコード
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""01: 制御構文・関数・型ヒント ------------------------------------------
テーマ: 部門別KPI(達成率)の評価
学習点: f文字列, 型ヒント, match文(Python 3.10+), enumerate, 内包表記
"""
from __future__ import annotations
def grade(rate: float) -> str:
"""達成率(0.0-)を5段階に分類する。match文はPython 3.10以降で利用可能。"""
match rate:
case r if r >= 1.20:
return "S (大幅超過)"
case r if r >= 1.00:
return "A (達成)"
case r if r >= 0.90:
return "B (僅差で未達)"
case r if r >= 0.70:
return "C (未達)"
case _:
return "D (要改善)"
def main() -> None:
# (部門名, 実績, 目標)
data: list[tuple[str, float, float]] = [
("営業一課", 1320.0, 1000.0),
("営業二課", 980.0, 1000.0),
("海外事業", 705.0, 1000.0),
("新規開発", 410.0, 1000.0),
("保守運用", 1010.0, 1000.0),
]
print(f"{'部門':<8}{'実績':>8}{'目標':>8}{'達成率':>9} 評価")
print("-" * 46)
for i, (name, actual, target) in enumerate(data, start=1):
rate = actual / target
print(f"{name:<8}{actual:>8.0f}{target:>8.0f}{rate:>8.1%} {grade(rate)}")
achieved = [d[0] for d in data if d[1] >= d[2]] # リスト内包表記
print("-" * 46)
print(f"達成部門数: {len(achieved)}/{len(data)} -> {', '.join(achieved)}")
print(f"全社達成率: {sum(d[1] for d in data) / sum(d[2] for d in data):.1%}")
if __name__ == "__main__":
main()
実行結果
部門 実績 目標 達成率 評価
----------------------------------------------
営業一課 1320 1000 132.0% S (大幅超過)
営業二課 980 1000 98.0% B (僅差で未達)
海外事業 705 1000 70.5% C (未達)
新規開発 410 1000 41.0% D (要改善)
保守運用 1010 1000 101.0% A (達成)
----------------------------------------------
達成部門数: 2/5 -> 営業一課, 保守運用
全社達成率: 88.5%