Contents
- 1 導入:なぜプロジェクトで学ぶべきか(ポートフォリオと実務スキル)
- 2 推奨環境と準備(Python 3.12推奨、venv/pyenv、pip、基本コマンド)
- 3 Python 3.12の注目点とプロジェクトでの活用例
- 4 プロジェクト一覧(選び方・各プロジェクトの詳細とスターターコード)
- 4.1 1) CLI TODOアプリ(Typer + SQLite)
- 4.2 2) 簡易Webスクレイパー+データ可視化
- 4.3 3) 家計簿・収支管理アプリ(SQLite + pandas)
- 4.4 4) 簡易チャットボット(LLM連携)
- 4.5 5) Discord ボット(discord.py)
- 4.6 6) 画像分類ミニプロジェクト(scikit-learn または PyTorch)
- 4.7 7) Webアプリ(FastAPI を使った簡易 API と Docker 化の基本)
- 4.8 8) ゲーム入門(Pygameで簡単ゲーム作成)
- 4.9 9) 自動化スクリプト(ファイル整理とブラウザ自動化の注意)
- 4.10 10) コマンドラインツールの作り方と配布(Typer/Click、パッケージ化)
- 5 品質向上:テスト・型チェック(pytest、mypy の導入と使い方)
- 6 デプロイ・公開・セキュリティと次のステップ(README テンプレ・よくあるつまずき・参考)
- 7 まとめ
導入:なぜプロジェクトで学ぶべきか(ポートフォリオと実務スキル)
学習の初期段階で短期間に成果を出すには、実務で使われる技術を小さなプロジェクトで手を動かして学ぶのが有効です。
この記事は初心者〜初級者向けに実務寄りのプロジェクト案、注意点、実装・テスト・公開の具体例を示します。
対象読者とこの記事の使い方
対象は学習1〜6ヶ月の学習者で、短時間で動く成果を作りGitHubで公開する流れを意識しています。
使い方の例は次の通りです。
- 目的や所要時間に合うプロジェクトを1つ選ぶ。
- スターターコードをローカルで動かし、テストを追加する。
- READMEに実行手順や注意点を記載して公開する。
推奨環境と準備(Python 3.12推奨、venv/pyenv、pip、基本コマンド)
ローカル開発に最低限必要なのはPython本体、仮想環境、パッケージ管理、テストツールです。Python 3.12を推奨しますが、プロジェクト要件に合わせてバージョンを固定してください。
環境構築(pyenv / venv / pip の手順)
典型的な手順の例を示します。Windowsは PowerShell / CMD のアクティベートコマンドを併記しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# pyenv(任意) pyenv install 3.12.x pyenv local 3.12.x # 仮想環境作成と有効化(UNIX) python -m venv .venv source .venv/bin/activate # Windows PowerShell python -m venv .venv .\.venv\Scripts\Activate.ps1 # Windows CMD python -m venv .venv .\.venv\Scripts\activate.bat # pip を最新に pip install -U pip setuptools wheel # 開発用パッケージ例(requirements-dev.txt を使うのが推奨) pip install -r requirements-dev.txt |
動作確認済みの依存関係例(requirements.txt の例)
以下は互換性を考えた例です。プロジェクトによって組み合わせが異なるため、ローカルでの動作確認を行ってください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# requirements.txt(例) typer==0.9.0 fastapi==0.95.2 uvicorn==0.22.0 pydantic==1.10.12 requests==2.31.0 beautifulsoup4==4.12.2 pandas==2.0.3 matplotlib==3.7.1 pytest==7.3.1 mypy==1.5.1 python-dotenv==1.0.0 discord.py==2.3.2 torch==2.1.0 |
環境変数・シークレット運用の基本
環境変数でAPIキーを管理し、ローカルでは .env と python-dotenv を使うのが簡便です。必ず .gitignore に .env を追加してください。公開環境ではシークレットマネージャ(GitHub Secrets / AWS Secrets Manager 等)を使うことを推奨します。
Python 3.12の注目点とプロジェクトでの活用例
Python 3.12 は型表現やランタイムの改善があり、コード品質や開発効率を向上させます。ここでは実務で使えるポイントと注意点を示します。
3.12の主要改善点と実務での活かし方
パターンマッチングや型ヒントの改善は可読性を上げ、型チェックツールの効果を高めます。型注釈の書き方に誤りがあると静的解析で警告が出るため、正しい記法を使ってください。
誤った例(避ける):
|
1 2 3 4 5 6 |
# NG: from typing import list, dict は誤り from typing import list, dict def summarize(items: list[str]) -> dict[str, int]: return {s: len(s) for s in items} |
正しい例(Python 3.9+ の組み込みジェネリックを使う):
|
1 2 3 |
def summarize(items: list[str]) -> dict[str, int]: return {s: len(s) for s in items} |
または typing から明示的に取り込む方法:
|
1 2 3 4 5 |
from typing import List, Dict def summarize(items: List[str]) -> Dict[str, int]: return {s: len(s) for s in items} |
型チェックはプロジェクト構成に依存するため、実行対象(パッケージ名や src ディレクトリ)を明示して実行してください。例えばパッケージ名が myapp なら mypy myapp --strict のように実行します。設定ファイルを使う場合は mypy.ini / pyproject.toml に設定を置いて mypy --config-file mypy.ini myapp のようにします。
プロジェクト一覧(選び方・各プロジェクトの詳細とスターターコード)
目的や学習フェーズに合わせてプロジェクトを選んでください。ここでは短時間で作れるものから少し手のかかるものまで、注意点とスターターコードを示します。
1) CLI TODOアプリ(Typer + SQLite)
短時間で実装できて学べることが多い定番プロジェクトです。CLI設計、ローカルDB、単体テストの基礎が学べます。
- 目的: CLIツール作成と永続化の基本を学ぶ
- 学べること: Typer(Click)、sqlite3、テスト、型注釈
- 必須ライブラリ: typer
- 難易度: 初心者〜初級
- 所要時間: 30分〜数時間
マイルストーンは次の通りです。
- add / list / remove の基本コマンドを実装する。
- SQLite に保存して永続化する。
- pytest で基本的なテストを書く(DBは一時化する)。
スターターコード(接続を安全に閉じ、コマンド名の衝突を避ける例):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# todo.py import os import sqlite3 from typing import Optional import typer app = typer.Typer() def _ensure_table(conn: sqlite3.Connection) -> None: conn.execute( "CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL)" ) def get_conn(db_path: str = "todo.db") -> sqlite3.Connection: # 接続は with 文で使う想定にする return sqlite3.connect(db_path, detect_types=sqlite3.PARSE_DECLTYPES) @app.command() def add(title: str, db: str = typer.Option("todo.db", envvar="TODO_DB")) -> None: """Add a todo.""" with get_conn(db) as conn: _ensure_table(conn) conn.execute("INSERT INTO todos (title) VALUES (?)", (title,)) @app.command(name="show") def list_todos(db: str = typer.Option("todo.db", envvar="TODO_DB")) -> None: """List todos. コマンド名は 'show' 等にして衝突を避ける('list' は予約語と衝突する可能性あり)。""" with get_conn(db) as conn: _ensure_table(conn) rows = conn.execute("SELECT id, title FROM todos").fetchall() for r in rows: typer.echo(f"{r[0]}: {r[1]}") @app.command() def remove(todo_id: int, db: str = typer.Option("todo.db", envvar="TODO_DB")) -> None: """Remove a todo by id.""" with get_conn(db) as conn: conn.execute("DELETE FROM todos WHERE id = ?", (todo_id,)) |
テスト時の DB 取り扱いについては次の点に注意してください。
- テストで実際のファイル DB を使うと状態が汚染されるため、tmp_path を使うか、':memory:' あるいは共有メモリ URI(必要に応じて)を利用してください。
- ':memory:' は接続ごとに独立するため、複数接続で共有したい場合は
sqlite3.connect("file::memory:?cache=shared", uri=True)のようにします。 - Pytest 例(簡易):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
from click.testing import CliRunner from todo import app import sqlite3 from pathlib import Path def test_add_and_show(tmp_path): runner = CliRunner() db = tmp_path / "todo.db" result = runner.invoke(app, ["add", "task1", "--db", str(db)]) assert result.exit_code == 0 result = runner.invoke(app, ["show", "--db", str(db)]) assert "task1" in result.output |
2) 簡易Webスクレイパー+データ可視化
外部サイトからデータを取得し解析する練習に向きます。取得は慎重に行い、robots.txt と利用規約を必ず確認してください。
- 目的: HTTP取得・HTMLパース・可視化
- 学べること: requests、BeautifulSoup、pandas、matplotlib
- 必須ライブラリ: requests, beautifulsoup4, pandas, matplotlib
スクレイピングの堅牢な実装例(robots.txt チェック、タイムアウト、User-Agent、例外処理含む):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import requests from bs4 import BeautifulSoup import pandas as pd import matplotlib.pyplot as plt from urllib import robotparser def can_fetch(url: str, user_agent: str = "my-bot/0.1") -> bool: rp = robotparser.RobotFileParser() rp.set_url(url.rstrip("/") + "/robots.txt") rp.read() return rp.can_fetch(user_agent, url) def fetch_quotes(url: str, timeout: int = 10, user_agent: str = "my-bot/0.1"): if not can_fetch(url, user_agent): raise RuntimeError("robots.txt でブロックされています") headers = {"User-Agent": user_agent} try: with requests.Session() as s: r = s.get(url, headers=headers, timeout=timeout) r.raise_for_status() soup = BeautifulSoup(r.text, "html.parser") quotes = [q.get_text(strip=True) for q in soup.select(".quote .text")] return quotes except requests.RequestException as e: # ここでログを残す、リトライ方針を入れるなど raise |
スクレイピングを行う前に、robots.txt とサイトの利用規約を確認し、アクセス頻度を制限して負荷を避けてください。
3) 家計簿・収支管理アプリ(SQLite + pandas)
永続化と集計を学ぶ定番です。CSV インポートや月次集計が学習効果の高い課題です。
- 目的: 収支の保存と分析
- 学べること: SQLite、pandas、集計処理、CSV入出力
簡単な集計例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import sqlite3 import pandas as pd from contextlib import closing db = "kakeibo.db" with closing(sqlite3.connect(db)) as conn: conn.execute( "CREATE TABLE IF NOT EXISTS tx (id INTEGER PRIMARY KEY, date TEXT, category TEXT, amount REAL)" ) conn.commit() monthly = pd.read_sql_query( "SELECT substr(date,1,7) as ym, sum(amount) as total FROM tx GROUP BY ym", sqlite3.connect(db) ) print(monthly) |
4) 簡易チャットボット(LLM連携)
外部LLMを利用することでAPI連携とプロンプト設計の基礎が学べます。セキュリティとコスト管理が重要です。
- 目的: LLM API の基本とプロンプト設計
- 学べること: HTTP API、環境変数、エラーハンドリング、出力フィルタ
安全な呼び出し例(requests と公式 SDK の両例、エラーハンドリング、簡易サニタイズ付き):
requests を使った例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import os import requests import time import logging API_KEY = os.getenv("OPENAI_API_KEY") if not API_KEY: raise SystemExit("OPENAI_API_KEY を設定してください") def sanitize_input(text: str) -> str: text = text.strip() if len(text) > 2000: text = text[:2000] return text def call_llm(prompt: str, retries: int = 3): url = "https://api.openai.com/v1/chat/completions" headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} payload = {"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": sanitize_input(prompt)}]} for i in range(retries): try: r = requests.post(url, headers=headers, json=payload, timeout=10) r.raise_for_status() return r.json() except requests.exceptions.HTTPError as e: if r.status_code == 429: backoff = 2 ** i time.sleep(backoff) continue logging.exception("API error") raise except requests.RequestException: logging.exception("Network error") raise |
公式 SDK(openai)を使う例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import os import openai import logging openai.api_key = os.getenv("OPENAI_API_KEY") def call_openai(prompt: str): try: resp = openai.ChatCompletion.create(model="gpt-3.5-turbo", messages=[{"role":"user","content":prompt}], timeout=10) return resp["choices"][0]["message"]["content"] except openai.error.OpenAIError: logging.exception("OpenAI API error") raise |
実務での注意点:
- 入力はサニタイズし、個人情報が含まれないようにする。
- レート制限とコストを監視し、必要ならトークン数制限やバッチ化を行う。
- ログは機密情報をマスクして保存し、監査用の最低限の情報を残す。
- 外部API呼び出しはモック化してテストする(pytest-mock等)。
5) Discord ボット(discord.py)
イベント駆動と非同期処理の基礎が学べます。discord.py v2以降は Intents の明示が必要です。
- 目的: チャットプラットフォーム連携の基本
- 学べること: 非同期処理、Bot登録、トークン管理
discord.py の基本例(Intents を明示):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import os import discord from discord.ext import commands intents = discord.Intents.default() intents.message_content = True # メッセージ内容を扱う場合は明示が必要 bot = commands.Bot(command_prefix="!", intents=intents) @bot.command() async def ping(ctx): await ctx.send("pong") bot.run(os.getenv("DISCORD_TOKEN")) |
注意点: 開発者ポータルで必要な Intents(Message Content 等)を有効にし、トークンは環境変数で管理してください。
6) 画像分類ミニプロジェクト(scikit-learn または PyTorch)
データ読み込みから学習、評価まで一通り体験できます。小規模データセットでまずは動作確認を行ってください。
- 目的: データ前処理・学習・評価
- 学べること: scikit-learn / PyTorch、前処理、評価指標
scikit-learn の簡単な例:
|
1 2 3 4 5 6 7 8 9 10 11 |
from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score data = load_digits() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42) clf = SVC() clf.fit(X_train, y_train) print("acc =", accuracy_score(y_test, clf.predict(X_test))) |
7) Webアプリ(FastAPI を使った簡易 API と Docker 化の基本)
API 設計とコンテナ化を学びます。Pydantic のメジャーバージョン違いで互換性が変わるため、バージョン管理に注意してください。
- 目的: API 設計・コンテナ化
- 学べること: FastAPI、Pydantic、uvicorn、Docker
FastAPI の最小例:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str price: float @app.post("/items") def create_item(item: Item): return {"name": item.name, "price": item.price} |
Dockerfile の最適化例(requirements を先に COPY してキャッシュを活かす):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN python -m pip install --upgrade pip && \ python -m pip install --no-cache-dir -r requirements.txt COPY . . # 非 root ユーザを作成して切り替える RUN useradd --create-home appuser && chown -R appuser /app USER appuser CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"] |
並びに .dockerignore を用意し、.git、.venv、pycache などを除外してください。
8) ゲーム入門(Pygameで簡単ゲーム作成)
ゲームループ、描画、入力処理の基本を学びます。フレームレート制御を忘れずに実装してください。
- 目的: ゲームループとイベント処理
- 学べること: 描画、入力処理、衝突判定
Pygame の基本ループ(FPS 制御あり):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import pygame pygame.init() win = pygame.display.set_mode((640, 480)) clock = pygame.time.Clock() fps = 60 run = True while run: for e in pygame.event.get(): if e.type == pygame.QUIT: run = False win.fill((0, 0, 0)) pygame.display.flip() clock.tick(fps) pygame.quit() |
9) 自動化スクリプト(ファイル整理とブラウザ自動化の注意)
日常のタスク自動化は学習効果が高い反面、利用規約や操作対象に注意が必要です。
- 目的: 日常タスクの自動化
- 学べること: pathlib、shutil、cron、Selenium/Playwright の注意点
ダウンロード整理の簡易例:
|
1 2 3 4 5 6 7 8 9 10 |
from pathlib import Path p = Path.home() / "Downloads" for f in p.iterdir(): if f.is_file(): ext = f.suffix.lower().lstrip(".") or "other" dest = p / ext dest.mkdir(exist_ok=True) f.rename(dest / f.name) |
ブラウザ自動化を行う場合は対象ウェブサイトの利用規約を確認し、認証情報の取り扱いに注意してください。
10) コマンドラインツールの作り方と配布(Typer/Click、パッケージ化)
CLI の設計とローカル配布を学びます。entry point を設定して pip install -e で開発インストールできます。
- 目的: CLI ツール設計と配布
- 学べること: Typer/Click、pyproject.toml、entry_points
簡単な Typer の例:
|
1 2 3 4 5 6 7 8 9 10 |
import typer app = typer.Typer() @app.command() def greet(name: str = "world"): typer.echo(f"hello {name}") if __name__ == "__main__": app() |
ローカルインストール:
|
1 2 |
pip install -e . |
品質向上:テスト・型チェック(pytest、mypy の導入と使い方)
テストと型チェックは品質担保の基本です。CI に組み込み自動化すると信頼性が向上します。
テスト・型チェック・CI の基本
最小限の導入手順と実務的なポイントを示します。型チェックやテストの対象はプロジェクト構成に合わせて指定してください。
- 基本パッケージ: pytest, pytest-cov, mypy, flake8 等を導入する。
- 型チェックはプロジェクトのパス(例: myapp や src)を指定して実行する。
mypy myapp --strictのように実行してください。 - mypy 設定例(mypy.ini):
|
1 2 3 4 5 |
[mypy] python_version = 3.12 warn_unused_configs = True strict = True |
- GitHub Actions での分割実行とキャッシュ例(抜粋):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# .github/workflows/ci.yml(抜粋) jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: "3.12" - name: Cache pip uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - run: pip install -r requirements-dev.txt - run: python -m pytest --maxfail=1 --disable-warnings -q - run: mypy myapp --config-file mypy.ini |
外部APIやDBを含むテストの実務例
- 外部APIはモック化する(pytest-mock/mocker を利用)。
- DB は tmp_path を使って一時ファイルで作成するか、テスト用の SQLite ファイルを作る。':memory:' の扱いに注意する。
- pytest の fixture 例(DB 一時化):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import sqlite3 import pytest from pathlib import Path @pytest.fixture def tmp_db(tmp_path: Path): db_file = tmp_path / "test.db" conn = sqlite3.connect(str(db_file)) conn.execute("CREATE TABLE todos (id INTEGER PRIMARY KEY, title TEXT)") conn.commit() conn.close() return str(db_file) |
- 外部APIのモック例(pytest-mock):
|
1 2 3 4 5 |
def test_call_openai(mocker): fake = {"choices": [{"message": {"content": "hello"}}]} mocker.patch("openai.ChatCompletion.create", return_value=fake) # 呼び出しテストを実行 |
デプロイ・公開・セキュリティと次のステップ(README テンプレ・よくあるつまずき・参考)
公開前に確認すべき点とセキュリティの基本をまとめます。公開はポートフォリオ評価を高めますが、情報漏洩には十分注意してください。
公開時のチェックリスト
公開前に最低限確認すべき項目は次の通りです。
- .gitignore に秘密ファイル(.env 等)を追加する。
- シークレットがコミット履歴に残っている場合は履歴から完全に削除する(下記の方法参照)。
- API キーは最小権限で発行し、使い終わったらローテーションする。
- テストと型チェックが通ることを確認する。
- README にセットアップ手順(UNIX と Windows 両方)と実行例を明記する。スクリーンショットは使わずテキストで操作手順を書く。
Git 履歴からの秘密情報削除(手順例)
- BFG を使う場合(簡易):
|
1 2 3 4 5 6 7 8 9 10 |
# ローカルにミラークローン git clone --mirror [メールアドレス削除]:you/repo.git cd repo.git # 例: .env を削除 bfg --delete-files .env git reflog expire --expire=now --all git gc --prune=now --aggressive # 強制プッシュ git push --force |
- git-filter-repo を使う場合:
|
1 2 3 4 5 |
git clone --mirror [メールアドレス削除]:you/repo.git cd repo.git git filter-repo --invert-paths --paths .env git push --force |
作業後は関連する API キーを再発行(ローテーション)し、不要な権限を削除してください。
.env とシークレット管理の実務
- ローカルでは .env を使い python-dotenv で読み込む。
- CI / 本番では GitHub Secrets やクラウドのシークレットマネージャを使い、コードやリポジトリにシークレットを置かない。
- ログ・監査ではシークレットや個人情報をマスクして保存する。
README テンプレ(必要最小限)
以下は画像を使わないテキスト中心の最小 README 例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# プロジェクト名 短い説明(1行)。 ## セットアップ UNIX: 1. python -m venv .venv 2. source .venv/bin/activate 3. pip install -r requirements.txt Windows (PowerShell): 1. python -m venv .venv 2. .\.venv\Scripts\Activate.ps1 3. pip install -r requirements.txt ## 実行例 - CLI: python todo.py add 'task' --db todo.db - Web: uvicorn app:app --reload ## テスト python -m pytest ## 注意事項 - APIキーは環境変数で設定してください(.env を使用する場合は .gitignore に追加)。 - 外部API 使用時はコストとレート制限に注意してください。 |
まとめ
小さな実務寄りプロジェクトを一つ選び、ローカルで動かしてテスト・型チェックを導入し、README に手順を明確に書いて公開することが学習効率を高めます。セキュリティや外部サービスの利用規約、ライブラリのバージョン互換性には常に注意してください。