Python総合演習問題50問

2025-11-30

はじめに

この記事では、Pythonの練習問題を初級・中級・上級の3段階、全50問収録しています。それぞれの問題には具体的な入出力条件解答例コードを掲載しています。コードをそのまま実行して動作を確認しながら学習を進めてください。


🟢 初級問題(問題1〜15)

問題1:基本データ型操作

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 整数 a = 10、浮動小数点数 b = 3.14、文字列 name = "Python"、ブーリアン flag = True を変数として定義する
  • a + b の結果を表示する(型も一緒に表示すること)
  • name を3回繰り返した文字列を表示する
  • flag の否定(not flag)を表示する

【期待する出力例】

合計: 13.14 (型: <class 'float'>)
繰り返し: PythonPythonPython
flagの否定: False

【解答例】

a = 10
b = 3.14
name = "Python"
flag = True

result = a + b
print(f"合計: {result} (型: {type(result)})")
print(f"繰り返し: {name * 3}")
print(f"flagの否定: {not flag}")

問題2:条件分岐の基本

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 変数 number に整数値を代入する(例: -507 などで動作確認すること)
  • number が正の数なら "〇〇は正の数です"、負の数なら "〇〇は負の数です"、ゼロなら "ゼロです" と表示する

【期待する出力例(number = -5 の場合)】

-5は負の数です

【解答例】

number = -5

if number > 0:
    print(f"{number}は正の数です")
elif number < 0:
    print(f"{number}は負の数です")
else:
    print("ゼロです")

問題3:FizzBuzz

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 1から30までの整数をループで処理する
  • 3の倍数のときは Fizz、5の倍数のときは Buzz、3と5の両方の倍数のときは FizzBuzz を表示する
  • それ以外はその数をそのまま表示する
  • すべての出力を1行ずつ表示する

【期待する出力例(最初の16行)】

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
...

【解答例】

for i in range(1, 31):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

問題4:リスト操作

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • numbers = [34, 7, 23, 32, 5, 62, 18, 45, 11, 29] というリストを使用する
  • 組み込み関数(max()min()sum()len())を使って最大値・最小値・平均値を求め、それぞれ表示する
  • 平均値は小数点以下2桁で表示する

【期待する出力例】

最大値: 62
最小値: 5
平均値: 26.60

【解答例】

numbers = [34, 7, 23, 32, 5, 62, 18, 45, 11, 29]

print(f"最大値: {max(numbers)}")
print(f"最小値: {min(numbers)}")
print(f"平均値: {sum(numbers) / len(numbers):.2f}")

問題5:辞書の基本操作

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • scores = {"Alice": 85, "Bob": 72, "Charlie": 91} という辞書を定義する
  • キー "Bob" の点数を検索して表示する
  • "Bob" の点数を 80 に更新して全体を表示する
  • "Charlie" を削除して全体を表示する
  • 存在しないキー "Dave" を検索した場合、"該当者なし" と表示する(get() を使うこと)

【期待する出力例】

Bobの点数: 72
更新後: {'Alice': 85, 'Bob': 80, 'Charlie': 91}
削除後: {'Alice': 85, 'Bob': 80}
Dave: 該当者なし

【解答例】

scores = {"Alice": 85, "Bob": 72, "Charlie": 91}

print(f"Bobの点数: {scores['Bob']}")

scores["Bob"] = 80
print(f"更新後: {scores}")

del scores["Charlie"]
print(f"削除後: {scores}")

print(f"Dave: {scores.get('Dave', '該当者なし')}")

問題6:四則演算関数

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 2つの数値 xy を引数として受け取り、和・差・積・商をタプルで返す関数 calc(x, y) を定義する
  • y == 0 のとき ZeroDivisionError を捕捉し、商の部分を None で返す
  • calc(10, 3)calc(10, 0) の両方を呼び出して結果を表示する

【期待する出力例】

calc(10, 3) → 和:13, 差:7, 積:30, 商:3.3333333333333335
calc(10, 0) → 和:10, 差:10, 積:0, 商:None

【解答例】

def calc(x, y):
    try:
        quotient = x / y
    except ZeroDivisionError:
        quotient = None
    return (x + y, x - y, x * y, quotient)

for args in [(10, 3), (10, 0)]:
    s, d, p, q = calc(*args)
    print(f"calc{args} → 和:{s}, 差:{d}, 積:{p}, 商:{q}")

問題7:ファイル読み込み

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • まずプログラム内で sample.txt というファイルを作成し、5行以上の文章を書き込む
  • 次にそのファイルを読み込み、総行数・空行を除いた行数・総文字数(改行除く)を表示する

【期待する出力例】

総行数: 6
空行を除いた行数: 5
総文字数(改行除く): 87

【解答例】

# ファイルを作成
with open("sample.txt", "w", encoding="utf-8") as f:
    f.write("Pythonは汎用プログラミング言語です。\n")
    f.write("シンプルな文法が特徴です。\n")
    f.write("データ分析や機械学習にも使われます。\n")
    f.write("Webアプリケーション開発にも活用できます。\n")
    f.write("初心者から上級者まで幅広く使われています。\n")
    f.write("\n")

# ファイルを読み込んで集計
with open("sample.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

total_lines = len(lines)
non_empty = sum(1 for line in lines if line.strip())
total_chars = sum(len(line.rstrip("\n")) for line in lines)

print(f"総行数: {total_lines}")
print(f"空行を除いた行数: {non_empty}")
print(f"総文字数(改行除く): {total_chars}")

問題8:ファイル書き込み

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • notes = ["買い物リスト", "牛乳", "卵", "パン", "りんご"] というリストをあらかじめ定義する
  • output.txt に各要素を1行ずつ書き込む
  • 書き込み後に再度読み込んで内容をそのまま表示し、「〇行書き込みました」と行数を表示する

【期待する出力例】

買い物リスト
牛乳
卵
パン
りんご
5行書き込みました

【解答例】

notes = ["買い物リスト", "牛乳", "卵", "パン", "りんご"]

with open("output.txt", "w", encoding="utf-8") as f:
    for note in notes:
        f.write(note + "\n")

with open("output.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

for line in lines:
    print(line, end="")
print(f"{len(lines)}行書き込みました")

問題9:Personクラスの作成

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • name(文字列)と age(整数)を属性として持つ Person クラスを定義する
  • introduce() メソッドで「私の名前は〇〇です。〇歳です。」と表示する
  • is_adult() メソッドで18歳以上なら True、未満なら False を返す
  • 3人分のインスタンスを作成し、それぞれ introduce()is_adult() の結果を表示する

【期待する出力例】

私の名前は田中太郎です。25歳です。成人: True
私の名前は鈴木花子です。17歳です。成人: False
私の名前は山田次郎です。18歳です。成人: True

【解答例】

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"私の名前は{self.name}です。{self.age}歳です。", end=" ")

    def is_adult(self):
        return self.age >= 18

people = [
    Person("田中太郎", 25),
    Person("鈴木花子", 17),
    Person("山田次郎", 18),
]

for p in people:
    p.introduce()
    print(f"成人: {p.is_adult()}")

問題10:例外処理の基礎

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 文字列のリスト inputs = ["42", "hello", "3.14", "", "100"] を定義する
  • 各要素を int() で変換しようとし、ValueError が発生した場合は "'〇〇' は整数に変換できません" と表示する
  • 変換成功した場合は "変換成功: 〇〇" と表示する

【期待する出力例】

変換成功: 42
'hello' は整数に変換できません
'3.14' は整数に変換できません
'' は整数に変換できません
変換成功: 100

【解答例】

inputs = ["42", "hello", "3.14", "", "100"]

for s in inputs:
    try:
        val = int(s)
        print(f"変換成功: {val}")
    except ValueError:
        print(f"'{s}' は整数に変換できません")

問題11:リスト内包表記

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • range(1, 21) を元に、リスト内包表記1行で偶数のみのリストを作成する
  • さらにリスト内包表記1行で、そのリストの各要素を2乗したリストも作成する
  • 両方のリストを表示する

【期待する出力例】

偶数リスト: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
2乗リスト: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

【解答例】

evens = [n for n in range(1, 21) if n % 2 == 0]
squares = [n ** 2 for n in evens]

print(f"偶数リスト: {evens}")
print(f"2乗リスト: {squares}")

問題12:文字列操作

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • text = "the quick brown fox jumps over the lazy dog" を使用する
  • 単語数を数えて表示する
  • 各単語の先頭を大文字にした文字列を表示する(title() は使わず、split()capitalize() を使うこと)
  • 文字列中に "the" が何回登場するかを表示する(大文字小文字は区別しない)

【期待する出力例】

単語数: 9
変換後: The Quick Brown Fox Jumps Over The Lazy Dog
'the'の登場回数: 2

【解答例】

text = "the quick brown fox jumps over the lazy dog"

words = text.split()
print(f"単語数: {len(words)}")

capitalized = " ".join(w.capitalize() for w in words)
print(f"変換後: {capitalized}")

count = text.lower().split().count("the")
print(f"'the'の登場回数: {count}")

問題13:円の計算

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • math モジュールの pi 定数を使用する(自分で3.14など定義しないこと)
  • 半径 r = 5 として、円周と面積を計算して表示する
  • 半径が負の値の場合は ValueError を発生させ、"半径は正の値を入力してください" と表示する
  • r = 5r = -3 両方で動作確認する

【期待する出力例】

半径5の円: 円周=31.42, 面積=78.54
半径は正の値を入力してください

【解答例】

import math

def circle_stats(r):
    if r < 0:
        raise ValueError("半径は正の値を入力してください")
    circumference = 2 * math.pi * r
    area = math.pi * r ** 2
    return circumference, area

for r in [5, -3]:
    try:
        c, a = circle_stats(r)
        print(f"半径{r}の円: 円周={c:.2f}, 面積={a:.2f}")
    except ValueError as e:
        print(e)

問題14:日付と時間

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • datetime モジュールを使用する
  • 現在の日付と時刻を YYYY年MM月DD日 HH:MM:SS の形式で表示する
  • 現在から100日後の日付を同じ形式で表示する
  • 今日が今年の何日目かを表示する(timetuple().tm_yday を使用)

【期待する出力例(実行日による)】

現在: 2025年06月15日 10:30:45
100日後: 2025年09月23日 10:30:45
今年の第166日目

【解答例】

from datetime import datetime, timedelta

now = datetime.now()
future = now + timedelta(days=100)

print(f"現在: {now.strftime('%Y年%m月%d日 %H:%M:%S')}")
print(f"100日後: {future.strftime('%Y年%m月%d日 %H:%M:%S')}")
print(f"今年の第{now.timetuple().tm_yday}日目")

問題15:mathモジュールの活用

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • math モジュールを使用する
  • 角度リスト [0, 30, 45, 60, 90] を度数法で定義し、各角度について sincostan(tan は90度除く)を計算して表示する
  • 角度は math.radians() でラジアンに変換すること
  • 各値は小数点以下4桁で表示する

【期待する出力例】

角度  sin     cos     tan
0°   0.0000  1.0000  0.0000
30°  0.5000  0.8660  0.5774
45°  0.7071  0.7071  1.0000
60°  0.8660  0.5000  1.7321
90°  1.0000  0.0000  -

【解答例】

import math

angles = [0, 30, 45, 60, 90]
print(f"{'角度':<5} {'sin':<8} {'cos':<8} {'tan'}")
for deg in angles:
    rad = math.radians(deg)
    s = math.sin(rad)
    c = math.cos(rad)
    t = f"{math.tan(rad):.4f}" if deg != 90 else "-"
    print(f"{deg}°{'':<3} {s:.4f}  {c:.4f}  {t}")

🟡 中級問題(問題16〜40)

問題16:BankAccountクラス

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • BankAccount クラスを定義し、口座名義(owner)と初期残高(balance、デフォルト0)を属性として持つ
  • deposit(amount): 正の金額のみ受け付け、それ以外は ValueError を発生させる
  • withdraw(amount): 残高不足の場合は ValueError("残高不足") を発生させる
  • get_balance(): 現在の残高を返す
  • 一連の操作(入金・出金・残高照会・残高不足の出金)を実行して結果を表示する

【期待する出力例】

入金後残高: 10000
出金後残高: 6500
現在残高: 6500
エラー: 残高不足

【解答例】

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("入金額は正の値でなければなりません")
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("残高不足")
        self.balance -= amount

    def get_balance(self):
        return self.balance

account = BankAccount("田中太郎")
account.deposit(10000)
print(f"入金後残高: {account.get_balance()}")

account.withdraw(3500)
print(f"出金後残高: {account.get_balance()}")
print(f"現在残高: {account.get_balance()}")

try:
    account.withdraw(10000)
except ValueError as e:
    print(f"エラー: {e}")

問題17:継承の実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 基底クラス Vehiclebrand(メーカー)・speed(最高速度km/h)を属性として持たせ、info() メソッドで基本情報を表示する
  • Car(Vehicle)num_doors(ドア数)を追加し、info() をオーバーライドしてドア数も表示する
  • Motorcycle(Vehicle)has_sidecar(サイドカーの有無、bool)を追加し、info() をオーバーライドする
  • 各クラスのインスタンスを1つずつ作成し、info() を呼び出す

【期待する出力例】

[Car] Toyota | 最高速度: 180km/h | ドア数: 4
[Motorcycle] Honda | 最高速度: 220km/h | サイドカー: なし

【解答例】

class Vehicle:
    def __init__(self, brand, speed):
        self.brand = brand
        self.speed = speed

    def info(self):
        print(f"[Vehicle] {self.brand} | 最高速度: {self.speed}km/h")

class Car(Vehicle):
    def __init__(self, brand, speed, num_doors):
        super().__init__(brand, speed)
        self.num_doors = num_doors

    def info(self):
        print(f"[Car] {self.brand} | 最高速度: {self.speed}km/h | ドア数: {self.num_doors}")

class Motorcycle(Vehicle):
    def __init__(self, brand, speed, has_sidecar):
        super().__init__(brand, speed)
        self.has_sidecar = has_sidecar

    def info(self):
        sidecar = "あり" if self.has_sidecar else "なし"
        print(f"[Motorcycle] {self.brand} | 最高速度: {self.speed}km/h | サイドカー: {sidecar}")

Car("Toyota", 180, 4).info()
Motorcycle("Honda", 220, False).info()

問題18:ポリモーフィズムの実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 基底クラス Shape に抽象的な area() メソッドを定義する(raise NotImplementedError を使う)
  • Circle(Shape):半径 r から面積を計算
  • Rectangle(Shape):幅 w と高さ h から面積を計算
  • Triangle(Shape):底辺 base と高さ height から面積を計算
  • 3つのインスタンスをリストに格納し、ループで area() を呼び出して全図形の面積を表示する

【期待する出力例】

Circle: 面積 = 78.54
Rectangle: 面積 = 24.00
Triangle: 面積 = 15.00

【解答例】

import math

class Shape:
    def area(self):
        raise NotImplementedError("サブクラスで実装してください")

class Circle(Shape):
    def __init__(self, r):
        self.r = r
    def area(self):
        return math.pi * self.r ** 2

class Rectangle(Shape):
    def __init__(self, w, h):
        self.w = w
        self.h = h
    def area(self):
        return self.w * self.h

class Triangle(Shape):
    def __init__(self, base, height):
        self.base = base
        self.height = height
    def area(self):
        return self.base * self.height / 2

shapes = [Circle(5), Rectangle(4, 6), Triangle(6, 5)]
for shape in shapes:
    print(f"{shape.__class__.__name__}: 面積 = {shape.area():.2f}")

問題19:カプセル化の実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • Student クラスを作成し、__name(文字列)と __score(0〜100の整数)をプライベート属性として持たせる
  • namescore のゲッター/セッターを @property で定義する
  • score のセッターで0未満または100超の値が設定された場合、ValueError を発生させる
  • 正常な操作と不正な操作の両方を実行して確認する

【期待する出力例】

名前: 山田, スコア: 85
スコア更新後: 90
エラー: スコアは0〜100の範囲で入力してください

【解答例】

class Student:
    def __init__(self, name, score):
        self.__name = name
        self.score = score  # セッター経由で設定

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

    @property
    def score(self):
        return self.__score

    @score.setter
    def score(self, value):
        if not (0 <= value <= 100):
            raise ValueError("スコアは0〜100の範囲で入力してください")
        self.__score = value

s = Student("山田", 85)
print(f"名前: {s.name}, スコア: {s.score}")

s.score = 90
print(f"スコア更新後: {s.score}")

try:
    s.score = 150
except ValueError as e:
    print(f"エラー: {e}")

問題20:特殊メソッドの活用

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • Vector2D クラスを作成し、xy 座標を属性として持つ
  • __str__: "Vector(x, y)" 形式で返す
  • __repr__: "Vector2D(x=〇, y=〇)" 形式で返す
  • __add__: 2つのベクトルを加算して新しい Vector2D を返す
  • __len__: ベクトルの成分数(常に2)を返す
  • 2つのインスタンスを作成して加算し、各特殊メソッドの動作を確認する

【期待する出力例】

str: Vector(1, 2)
repr: Vector2D(x=1, y=2)
v1 + v2: Vector(4, 6)
len: 2

【解答例】

class Vector2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

    def __repr__(self):
        return f"Vector2D(x={self.x}, y={self.y})"

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def __len__(self):
        return 2

v1 = Vector2D(1, 2)
v2 = Vector2D(3, 4)
print(f"str: {v1}")
print(f"repr: {repr(v1)}")
print(f"v1 + v2: {v1 + v2}")
print(f"len: {len(v1)}")

問題21:独自例外の定義

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • Exception を継承した InsufficientFundsError を定義し、不足額を属性として保持する
  • BankAccount クラス(問題16と同様)の withdraw() メソッドで残高不足時に InsufficientFundsError を発生させる
  • エラー発生時に "残高不足: 〇〇円不足しています" と不足額を表示する

【期待する出力例】

残高不足: 2000円不足しています

【解答例】

class InsufficientFundsError(Exception):
    def __init__(self, shortage):
        self.shortage = shortage
        super().__init__(f"残高不足: {shortage}円不足しています")

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(amount - self.balance)
        self.balance -= amount

account = BankAccount(3000)
try:
    account.withdraw(5000)
except InsufficientFundsError as e:
    print(e)

問題22:デコレータの作成

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 関数の実行時間を計測して "〇〇: 〇.〇〇〇〇秒" と表示するデコレータ timer を作成する
  • functools.wraps を使って元の関数名を保持する
  • 1〜10000の合計を計算する関数と、0.1秒スリープする関数の2つに @timer を適用して実行する

【期待する出力例】

sum_numbers: 0.0003秒
合計: 50005000
slow_function: 0.1001秒

【解答例】

import time
import functools

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() - start
        print(f"{func.__name__}: {elapsed:.4f}秒")
        return result
    return wrapper

@timer
def sum_numbers(n):
    return sum(range(n + 1))

@timer
def slow_function():
    time.sleep(0.1)

result = sum_numbers(10000)
print(f"合計: {result}")
slow_function()

問題23:フィボナッチジェネレータ

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • yield を使ったジェネレータ関数 fibonacci(n) を作成し、n 番目までのフィボナッチ数列を生成する
  • fibonacci(10) で最初の10個の値をリストとして取得し表示する
  • ジェネレータを使って50を超える最初のフィボナッチ数を next() を使わずに for ループで見つけて表示する

【期待する出力例】

最初の10個: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
50を超える最初の値: 55

【解答例】

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

print(f"最初の10個: {list(fibonacci(10))}")

for val in fibonacci(20):
    if val > 50:
        print(f"50を超える最初の値: {val}")
        break

問題24:コンテキストマネージャ

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • __enter____exit__ を実装したクラス ManagedFile を作成する
  • ファイルを開く際に "ファイルを開きました: 〇〇"、閉じる際に "ファイルを閉じました: 〇〇" と表示する
  • __exit__ で例外が発生した場合のログも出力する
  • with ManagedFile("test.txt") as f: の形式で使用できることを確認する

【期待する出力例】

ファイルを開きました: test.txt
書き込み完了
ファイルを閉じました: test.txt

【解答例】

class ManagedFile:
    def __init__(self, filename, mode="w", encoding="utf-8"):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding
        self.file = None

    def __enter__(self):
        print(f"ファイルを開きました: {self.filename}")
        self.file = open(self.filename, self.mode, encoding=self.encoding)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f"例外発生: {exc_val}")
        if self.file:
            self.file.close()
        print(f"ファイルを閉じました: {self.filename}")
        return False  # 例外を伝播させる

with ManagedFile("test.txt") as f:
    f.write("Hello, Context Manager!\n")
    print("書き込み完了")

問題25:ログ出力の実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • logging モジュールを使用し、ログレベル DEBUG 以上を app.log ファイルに出力するよう設定する
  • フォーマットは [%(levelname)s] %(asctime)s - %(message)s とする
  • DEBUGINFOWARNINGERRORCRITICAL 各レベルのメッセージを1つずつ出力する
  • 最後に app.log を読み込んで内容を表示する

【期待する出力例(ファイル内容)】

[DEBUG] 2025-06-15 10:00:00,000 - デバッグ情報
[INFO] 2025-06-15 10:00:00,001 - 処理開始
[WARNING] 2025-06-15 10:00:00,002 - 注意が必要です
[ERROR] 2025-06-15 10:00:00,003 - エラーが発生しました
[CRITICAL] 2025-06-15 10:00:00,004 - 致命的なエラーです

【解答例】

import logging

logging.basicConfig(
    filename="app.log",
    level=logging.DEBUG,
    format="[%(levelname)s] %(asctime)s - %(message)s",
    encoding="utf-8"
)

logging.debug("デバッグ情報")
logging.info("処理開始")
logging.warning("注意が必要です")
logging.error("エラーが発生しました")
logging.critical("致命的なエラーです")

with open("app.log", "r", encoding="utf-8") as f:
    print(f.read())

問題26:JSONデータの処理

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 以下の辞書データを students.json に保存する(インデント=2、日本語はそのまま保存)
    {"students": [{"name": "Alice", "score": 85}, {"name": "Bob", "score": 72}, {"name": "Charlie", "score": 91}]}
  • 保存したファイルを読み込み、スコアが80以上の学生名だけをリストで表示する

【期待する出力例】

80以上の学生: ['Alice', 'Charlie']

【解答例】

import json

data = {
    "students": [
        {"name": "Alice", "score": 85},
        {"name": "Bob", "score": 72},
        {"name": "Charlie", "score": 91}
    ]
}

with open("students.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("students.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

high_scorers = [s["name"] for s in loaded["students"] if s["score"] >= 80]
print(f"80以上の学生: {high_scorers}")

問題27:CSVデータの操作

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 以下のデータを products.csv として作成する:
    ヘッダー: name,price,quantity
    データ: Apple/150/10, Banana/80/25, Cherry/300/5, Grape/500/8
  • CSVを読み込み、各商品の合計金額(price × quantity)を計算して新しい列 total を加えた products_updated.csv を出力する
  • 更新後のCSVの内容を表示する

【期待する出力例】

name,price,quantity,total
Apple,150,10,1500
Banana,80,25,2000
Cherry,300,5,1500
Grape,500,8,4000

【解答例】

import csv

rows = [
    ["name", "price", "quantity"],
    ["Apple", 150, 10],
    ["Banana", 80, 25],
    ["Cherry", 300, 5],
    ["Grape", 500, 8],
]

with open("products.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

with open("products.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    updated = []
    for row in reader:
        row["total"] = int(row["price"]) * int(row["quantity"])
        updated.append(row)

fieldnames = ["name", "price", "quantity", "total"]
with open("products_updated.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(updated)

with open("products_updated.csv", "r", encoding="utf-8") as f:
    print(f.read())

問題28:SQLiteデータベース接続

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • school.db に接続し、students テーブルを作成する(カラム: id INTEGER PRIMARY KEY AUTOINCREMENTname TEXTgrade INTEGERscore REAL
  • テーブルが既に存在する場合はエラーにならないようにする(CREATE TABLE IF NOT EXISTS
  • 3件のデータを INSERT し、全件を SELECT して表示する

【期待する出力例】

id=1, name=田中, grade=2, score=85.5
id=2, name=鈴木, grade=3, score=91.0
id=3, name=佐藤, grade=1, score=78.0

【解答例】

import sqlite3

conn = sqlite3.connect("school.db")
cur = conn.cursor()

cur.execute("""
    CREATE TABLE IF NOT EXISTS students (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT,
        grade INTEGER,
        score REAL
    )
""")

students = [("田中", 2, 85.5), ("鈴木", 3, 91.0), ("佐藤", 1, 78.0)]
cur.executemany("INSERT INTO students (name, grade, score) VALUES (?, ?, ?)", students)
conn.commit()

for row in cur.execute("SELECT * FROM students"):
    print(f"id={row[0]}, name={row[1]}, grade={row[2]}, score={row[3]}")

conn.close()

問題29:CRUD操作の実装

【問題】
問題28で作成した school.dbstudents テーブルに対して、以下のCRUD操作をすべて実装してください。

  • Create: 新しい学生を1件追加する関数 create_student(conn, name, grade, score)
  • Read: 全件取得する read_all(conn) と、id で1件取得する read_by_id(conn, id)
  • Update: 指定 idscore を更新する update_score(conn, id, score)
  • Delete: 指定 id を削除する delete_student(conn, id)
  • 各関数を順番に呼び出して動作を確認する

【期待する出力例】

追加後全件: [(1, '山田', 1, 88.0)]
id=1: (1, '山田', 1, 88.0)
更新後: (1, '山田', 1, 95.0)
削除後全件: []

【解答例】

import sqlite3

def get_connection():
    conn = sqlite3.connect(":memory:")
    conn.execute("""CREATE TABLE students
                    (id INTEGER PRIMARY KEY AUTOINCREMENT,
                     name TEXT, grade INTEGER, score REAL)""")
    return conn

def create_student(conn, name, grade, score):
    conn.execute("INSERT INTO students (name, grade, score) VALUES (?, ?, ?)",
                 (name, grade, score))
    conn.commit()

def read_all(conn):
    return conn.execute("SELECT * FROM students").fetchall()

def read_by_id(conn, id):
    return conn.execute("SELECT * FROM students WHERE id=?", (id,)).fetchone()

def update_score(conn, id, score):
    conn.execute("UPDATE students SET score=? WHERE id=?", (score, id))
    conn.commit()

def delete_student(conn, id):
    conn.execute("DELETE FROM students WHERE id=?", (id,))
    conn.commit()

conn = get_connection()
create_student(conn, "山田", 1, 88.0)
print(f"追加後全件: {read_all(conn)}")
print(f"id=1: {read_by_id(conn, 1)}")
update_score(conn, 1, 95.0)
print(f"更新後: {read_by_id(conn, 1)}")
delete_student(conn, 1)
print(f"削除後全件: {read_all(conn)}")
conn.close()

問題30:データ永続化クラス

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • UserSettings クラスを作成し、settings.json にユーザー設定を読み書きする
  • get(key, default=None): キーの値を返す(存在しない場合は default
  • set(key, value): キーと値を設定してファイルに即保存
  • delete(key): キーを削除してファイルに即保存
  • インスタンスを2回作成しても設定が引き継がれることを確認する

【期待する出力例】

theme: dark
language: ja
theme削除後: None
再起動後のlanguage: ja

【解答例】

import json
import os

class UserSettings:
    def __init__(self, filepath="settings.json"):
        self.filepath = filepath
        self._data = {}
        if os.path.exists(filepath):
            with open(filepath, "r", encoding="utf-8") as f:
                self._data = json.load(f)

    def _save(self):
        with open(self.filepath, "w", encoding="utf-8") as f:
            json.dump(self._data, f, ensure_ascii=False, indent=2)

    def get(self, key, default=None):
        return self._data.get(key, default)

    def set(self, key, value):
        self._data[key] = value
        self._save()

    def delete(self, key):
        self._data.pop(key, None)
        self._save()

s1 = UserSettings()
s1.set("theme", "dark")
s1.set("language", "ja")
print(f"theme: {s1.get('theme')}")
print(f"language: {s1.get('language')}")

s1.delete("theme")
print(f"theme削除後: {s1.get('theme')}")

s2 = UserSettings()
print(f"再起動後のlanguage: {s2.get('language')}")

問題31:HTTPリクエストの送信

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • requests ライブラリを使用して https://jsonplaceholder.typicode.com/posts/1 にGETリクエストを送信する
  • ステータスコードを表示する
  • レスポンスのJSONから userIdtitlebody を取り出して表示する
  • 接続エラーの場合は requests.exceptions.ConnectionError を捕捉してメッセージを表示する

【期待する出力例】

ステータスコード: 200
userId: 1
title: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
body: quia et suscipit...

【解答例】

import requests

url = "https://jsonplaceholder.typicode.com/posts/1"

try:
    response = requests.get(url, timeout=10)
    print(f"ステータスコード: {response.status_code}")

    data = response.json()
    print(f"userId: {data['userId']}")
    print(f"title: {data['title']}")
    print(f"body: {data['body'][:30]}...")
except requests.exceptions.ConnectionError:
    print("接続エラーが発生しました")

問題32:REST APIクライアント

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • https://jsonplaceholder.typicode.com/users から全ユーザーを取得する
  • 取得したユーザーの中から username が5文字以上のユーザーのみを絞り込む
  • 絞り込んだユーザーの nameusernameemail を一覧表示する
  • 総ユーザー数と絞り込み後の件数を表示する

【期待する出力例(一部)】

総ユーザー数: 10 / 絞り込み後: 8
Leanne Graham (Bret) - Sincere@april.biz
...

【解答例】

import requests

response = requests.get("https://jsonplaceholder.typicode.com/users", timeout=10)
users = response.json()

filtered = [u for u in users if len(u["username"]) >= 5]
print(f"総ユーザー数: {len(users)} / 絞り込み後: {len(filtered)}")

for u in filtered:
    print(f"{u['name']} ({u['username']}) - {u['email']}")

問題33:データ可視化の基礎

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • matplotlib を使用して1つの Figure に2つのサブプロット(1行2列)を作成する
  • 左: x = [1,2,3,4,5]y = [2,4,1,3,5] の折れ線グラフ(タイトル: "折れ線グラフ"、マーカー付き)
  • 右: 科目と点数のデータ(国語:80, 数学:65, 英語:90, 理科:75, 社会:85)の棒グラフ(タイトル: "科目別点数")
  • graph.png として保存する

【解答例】

import matplotlib.pyplot as plt
import matplotlib

matplotlib.rcParams['font.family'] = 'IPAexGothic'  # 日本語フォント(環境に合わせて変更)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

x = [1, 2, 3, 4, 5]
y = [2, 4, 1, 3, 5]
ax1.plot(x, y, marker="o")
ax1.set_title("折れ線グラフ")

subjects = ["国語", "数学", "英語", "理科", "社会"]
scores = [80, 65, 90, 75, 85]
ax2.bar(subjects, scores)
ax2.set_title("科目別点数")

plt.tight_layout()
plt.savefig("graph.png")
print("graph.png を保存しました")

問題34:Pandasによるデータ分析

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 以下のデータを持つCSVファイル exam.csv を作成する(列: name, math, english, science、5名分のデータ)
  • pandas で読み込み、describe() で基本統計量を表示する
  • 各生徒の合計点と平均点を新列として追加して表示する
  • 合計点が最も高い生徒の名前を表示する

【期待する出力例】

     name  math  english  science  total    avg
0   Alice    80       90       85    255  85.00
1     Bob    70       65       80    215  71.67
...
最高得点者: Alice

【解答例】

import pandas as pd

data = {
    "name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
    "math": [80, 70, 90, 60, 75],
    "english": [90, 65, 85, 70, 95],
    "science": [85, 80, 70, 65, 88],
}
df = pd.DataFrame(data)
df.to_csv("exam.csv", index=False)

df = pd.read_csv("exam.csv")
print(df.describe())

subjects = ["math", "english", "science"]
df["total"] = df[subjects].sum(axis=1)
df["avg"] = df[subjects].mean(axis=1).round(2)
print(df)

best = df.loc[df["total"].idxmax(), "name"]
print(f"最高得点者: {best}")

問題35:正規表現の活用

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 以下のテキストからメールアドレスと日本の電話番号(ハイフン区切り、市外局番含む)をすべて抽出する
  • テキスト例: "連絡先: alice@example.com, 電話: 03-1234-5678, bob.smith@test.co.jp, 090-9876-5432"
  • 抽出した結果をそれぞれリストで表示する

【期待する出力例】

メールアドレス: ['alice@example.com', 'bob.smith@test.co.jp']
電話番号: ['03-1234-5678', '090-9876-5432']

【解答例】

import re

text = "連絡先: alice@example.com, 電話: 03-1234-5678, bob.smith@test.co.jp, 090-9876-5432"

emails = re.findall(r'[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}', text)
phones = re.findall(r'\d{2,4}-\d{3,4}-\d{4}', text)

print(f"メールアドレス: {emails}")
print(f"電話番号: {phones}")

問題36:マルチスレッド処理

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • threading.Thread を使い、0.5秒スリープして "タスク〇〇 完了" と表示する関数 task(name) を定義する
  • タスクA・B・Cを3つのスレッドで同時に起動する
  • 全スレッドが完了してから "すべてのタスクが完了しました" と表示する(join() を使うこと)
  • スレッドなしの逐次実行と比べて実行時間が短くなっていることを確認するため、開始・終了時刻を表示する

【期待する出力例】

開始
タスクB 完了
タスクA 完了
タスクC 完了
すべてのタスクが完了しました
経過時間: 0.50秒

【解答例】

import threading
import time

def task(name):
    time.sleep(0.5)
    print(f"タスク{name} 完了")

start = time.time()
print("開始")

threads = [threading.Thread(target=task, args=(n,)) for n in ["A", "B", "C"]]
for t in threads:
    t.start()
for t in threads:
    t.join()

print("すべてのタスクが完了しました")
print(f"経過時間: {time.time() - start:.2f}秒")

問題37:イテレータの実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • __iter____next__ を実装した Countdown クラスを作成する
  • コンストラクタで開始値 start を受け取り、start から 0 までの整数を順番に返す
  • 0以下になったら StopIteration を発生させる
  • Countdown(5)for ループで使用して出力する

【期待する出力例】

5
4
3
2
1
0

【解答例】

class Countdown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < 0:
            raise StopIteration
        val = self.current
        self.current -= 1
        return val

for n in Countdown(5):
    print(n)

問題38:プロパティの使用

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • Temperature クラスを作成し、内部では摂氏(_celsius)で温度を保持する
  • celsius プロパティ: ゲッターとセッターを実装し、セッターでは −273.15未満の値を ValueError で拒否する
  • fahrenheit プロパティ: ゲッターのみ実装し、摂氏からの変換値を返す(°C × 9/5 + 32
  • 100℃・−300℃(エラー確認)・0℃ の3パターンで動作確認する

【期待する出力例】

100℃ = 212.0°F
エラー: -273.15未満の温度は存在しません
0℃ = 32.0°F

【解答例】

class Temperature:
    def __init__(self, celsius=0):
        self.celsius = celsius

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("-273.15未満の温度は存在しません")
        self._celsius = value

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

for c in [100, -300, 0]:
    try:
        t = Temperature(c)
        print(f"{c}℃ = {t.fahrenheit}°F")
    except ValueError as e:
        print(f"エラー: {e}")

問題39:モックオブジェクトの使用

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 外部API(requests.get)を呼び出す関数 fetch_user(user_id) を作成する(戻り値は {"id": user_id, "name": "..."} の辞書)
  • unittest.mock.patch を使って requests.get をモック化し、実際のHTTPリクエストを発生させずにテストを書く
  • unittest.TestCase を継承したテストクラスを作成し、正常レスポンスのテストケースを最低1つ実装する

【期待する出力例】

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

【解答例】

import unittest
from unittest.mock import patch, MagicMock
import requests

def fetch_user(user_id):
    response = requests.get(f"https://api.example.com/users/{user_id}")
    return response.json()

class TestFetchUser(unittest.TestCase):
    @patch("requests.get")
    def test_fetch_user_success(self, mock_get):
        mock_response = MagicMock()
        mock_response.json.return_value = {"id": 1, "name": "Alice"}
        mock_get.return_value = mock_response

        result = fetch_user(1)

        mock_get.assert_called_once_with("https://api.example.com/users/1")
        self.assertEqual(result["id"], 1)
        self.assertEqual(result["name"], "Alice")

if __name__ == "__main__":
    unittest.main()

問題40:パッケージ作成

【問題】
以下の条件をすべて満たすパッケージを作成してください。

  • パッケージ名: mathutils
  • mathutils/basic.py: addsubtractmultiplydivide 関数を実装(divide はゼロ除算で ValueError
  • mathutils/stats.py: meanmedianmode 関数を実装(標準ライブラリのみ使用)
  • mathutils/__init__.py: 両モジュールから全関数をインポートしてパッケージ直下から使えるようにする
  • パッケージ外から from mathutils import add, mean の形式でインポートして動作確認する

【期待する出力例】

add(3,4) = 7
mean([1,2,3,4,5]) = 3.0
median([3,1,4,1,5]) = 3
mode([1,2,2,3]) = 2

【解答例】

# mathutils/basic.py
def add(a, b): return a + b
def subtract(a, b): return a - b
def multiply(a, b): return a * b
def divide(a, b):
    if b == 0:
        raise ValueError("ゼロ除算エラー")
    return a / b

# mathutils/stats.py
import statistics
def mean(data): return statistics.mean(data)
def median(data): return statistics.median(data)
def mode(data): return statistics.mode(data)

# mathutils/__init__.py
from .basic import add, subtract, multiply, divide
from .stats import mean, median, mode

# main.py(パッケージ外)
from mathutils import add, mean, median, mode

print(f"add(3,4) = {add(3, 4)}")
print(f"mean([1,2,3,4,5]) = {mean([1,2,3,4,5])}")
print(f"median([3,1,4,1,5]) = {median([3,1,4,1,5])}")
print(f"mode([1,2,2,3]) = {mode([1,2,2,3])}")

🔴 上級問題(問題41〜50)

問題41:Flaskによる簡単なWebアプリ

【問題】
以下の条件をすべて満たすFlaskアプリケーションを作成してください。

  • ルート /: "Hello, Flask!" を返す
  • ルート /greet/<name>: "こんにちは、〇〇さん!" を返す
  • ルート /calc: クエリパラメータ abop(add/sub/mul/div)を受け取り計算結果をJSONで返す
  • 例: /calc?a=10&b=3&op=add{"result": 13}
  • debug=Falseport=5000 で起動するコードを含める

【解答例】

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello, Flask!"

@app.route("/greet/<name>")
def greet(name):
    return f"こんにちは、{name}さん!"

@app.route("/calc")
def calc():
    a = float(request.args.get("a", 0))
    b = float(request.args.get("b", 0))
    op = request.args.get("op", "add")

    ops = {"add": a + b, "sub": a - b, "mul": a * b}
    if op == "div":
        if b == 0:
            return jsonify({"error": "ゼロ除算"}), 400
        result = a / b
    else:
        result = ops.get(op)
        if result is None:
            return jsonify({"error": "不正な演算子"}), 400

    return jsonify({"result": result})

if __name__ == "__main__":
    app.run(debug=False, port=5000)

問題42:asyncioによる非同期処理

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • asyncio を使用して、asyncio.sleep() で待機をシミュレートする非同期タスクを作成する
  • タスク: fetch_data(name, delay)delay秒待機後に "name のデータ取得完了" を返す)
  • タスクA(2秒)、タスクB(1秒)、タスクC(1.5秒)を asyncio.gather() で並列実行する
  • 全タスクを合計した実行時間が約2秒(逐次実行なら4.5秒)になることをコメントで示す

【期待する出力例】

タスクB のデータ取得完了
タスクC のデータ取得完了
タスクA のデータ取得完了
総実行時間: 2.00秒

【解答例】

import asyncio
import time

async def fetch_data(name, delay):
    await asyncio.sleep(delay)
    msg = f"{name} のデータ取得完了"
    print(msg)
    return msg

async def main():
    start = time.time()
    # 並列実行: 最長タスク(2秒)が律速 → 合計約2秒
    results = await asyncio.gather(
        fetch_data("タスクA", 2),
        fetch_data("タスクB", 1),
        fetch_data("タスクC", 1.5),
    )
    print(f"総実行時間: {time.time() - start:.2f}秒")

asyncio.run(main())

問題43:SQLAlchemyによるORM

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • SQLAlchemyDeclarativeBase を使って Product モデルを定義する(カラム: idnamepricestock
  • インメモリのSQLite(sqlite:///:memory:)を使用する
  • 3件のProductを追加し、価格が1000円以上のもののみを取得して表示する
  • 最後に全商品の平均価格を func.avg() を使って表示する

【期待する出力例】

1000円以上の商品:
  ノートPC: 80000円 (在庫: 10)
  スマートフォン: 50000円 (在庫: 25)
全商品の平均価格: 43666.67円

【解答例】

from sqlalchemy import create_engine, Column, Integer, String, Float, func
from sqlalchemy.orm import DeclarativeBase, Session

engine = create_engine("sqlite:///:memory:")

class Base(DeclarativeBase):
    pass

class Product(Base):
    __tablename__ = "products"
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String)
    price = Column(Float)
    stock = Column(Integer)

Base.metadata.create_all(engine)

with Session(engine) as session:
    session.add_all([
        Product(name="ノートPC", price=80000, stock=10),
        Product(name="マウス", price=1000, stock=100),
        Product(name="スマートフォン", price=50000, stock=25),
    ])
    session.commit()

    print("1000円以上の商品:")
    for p in session.query(Product).filter(Product.price >= 1000).all():
        print(f"  {p.name}: {p.price:.0f}円 (在庫: {p.stock})")

    avg = session.query(func.avg(Product.price)).scalar()
    print(f"全商品の平均価格: {avg:.2f}円")

問題44:Flask REST APIサーバー

【問題】
Flaskを使って、以下のエンドポイントを持つTodoリスト管理APIを実装してください。

  • GET /todos: 全Todoを返す
  • POST /todos: JSONボディ {"title": "..."} でTodoを追加し、追加したデータをステータス201で返す
  • PUT /todos/<id>: 指定IDのTodoの doneTrue に更新する
  • DELETE /todos/<id>: 指定IDのTodoを削除する
  • データはメモリ上のリストで管理する(DBは不要)

【解答例】

from flask import Flask, jsonify, request, abort

app = Flask(__name__)

todos = []
next_id = 1

@app.route("/todos", methods=["GET"])
def get_todos():
    return jsonify(todos)

@app.route("/todos", methods=["POST"])
def create_todo():
    global next_id
    data = request.get_json()
    if not data or "title" not in data:
        abort(400)
    todo = {"id": next_id, "title": data["title"], "done": False}
    todos.append(todo)
    next_id += 1
    return jsonify(todo), 201

@app.route("/todos/<int:todo_id>", methods=["PUT"])
def complete_todo(todo_id):
    todo = next((t for t in todos if t["id"] == todo_id), None)
    if not todo:
        abort(404)
    todo["done"] = True
    return jsonify(todo)

@app.route("/todos/<int:todo_id>", methods=["DELETE"])
def delete_todo(todo_id):
    global todos
    original = len(todos)
    todos = [t for t in todos if t["id"] != todo_id]
    if len(todos) == original:
        abort(404)
    return "", 204

if __name__ == "__main__":
    app.run(debug=False, port=5000)

問題45:包括的なユニットテスト

【問題】
以下の条件をすべて満たすテストスイートを作成してください。

  • 問題6の calc() 関数に対して unittest で以下のテストケースを実装する
  • 正常系: calc(10, 2) の和・差・積・商がすべて正しいこと
  • 正常系: calc(0, 5)calc(-3, 7) のそれぞれの和が正しいこと
  • 異常系: calc(10, 0) の商が None になること
  • テストを実行して全テストがパスすることを確認する

【期待する出力例】

......
----------------------------------------------------------------------
Ran 5 tests in 0.001s

OK

【解答例】

import unittest

def calc(x, y):
    try:
        quotient = x / y
    except ZeroDivisionError:
        quotient = None
    return (x + y, x - y, x * y, quotient)

class TestCalc(unittest.TestCase):

    def test_basic_operations(self):
        s, d, p, q = calc(10, 2)
        self.assertEqual(s, 12)
        self.assertEqual(d, 8)
        self.assertEqual(p, 20)
        self.assertAlmostEqual(q, 5.0)

    def test_zero_numerator(self):
        s, _, _, _ = calc(0, 5)
        self.assertEqual(s, 5)

    def test_negative(self):
        s, _, _, _ = calc(-3, 7)
        self.assertEqual(s, 4)

    def test_zero_division_returns_none(self):
        _, _, _, q = calc(10, 0)
        self.assertIsNone(q)

    def test_negative_result(self):
        _, d, _, _ = calc(3, 10)
        self.assertEqual(d, -7)

if __name__ == "__main__":
    unittest.main()

問題46:デザインパターンの実装

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • Observerパターンを実装する
  • EventEmitter クラス: subscribe(event, callback)unsubscribe(event, callback)emit(event, data) メソッドを持つ
  • 同一イベントに複数のコールバックを登録できること
  • "click" イベントと "input" イベントにそれぞれコールバックを登録し、emit を呼び出して動作を確認する
  • unsubscribe 後に同イベントを emit しても解除したコールバックが呼ばれないことを確認する

【期待する出力例】

[Logger] click: {'x': 100, 'y': 200}
[UI] ボタンがクリックされました
[Input] 入力値: hello
unsubscribe後:
[UI] ボタンがクリックされました

【解答例】

from collections import defaultdict

class EventEmitter:
    def __init__(self):
        self._listeners = defaultdict(list)

    def subscribe(self, event, callback):
        self._listeners[event].append(callback)

    def unsubscribe(self, event, callback):
        self._listeners[event] = [
            cb for cb in self._listeners[event] if cb != callback
        ]

    def emit(self, event, data=None):
        for callback in self._listeners[event]:
            callback(data)

emitter = EventEmitter()

def logger(data):
    print(f"[Logger] click: {data}")

def ui_handler(data):
    print("[UI] ボタンがクリックされました")

def input_handler(data):
    print(f"[Input] 入力値: {data}")

emitter.subscribe("click", logger)
emitter.subscribe("click", ui_handler)
emitter.subscribe("input", input_handler)

emitter.emit("click", {"x": 100, "y": 200})
emitter.emit("input", "hello")

emitter.unsubscribe("click", logger)
print("unsubscribe後:")
emitter.emit("click", {"x": 50, "y": 75})

問題47:データ可視化ダッシュボード

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • matplotlib を使って2行2列(4サブプロット)のダッシュボードを作成する
  • ①月別売上の折れ線グラフ(1〜12月)
  • ②カテゴリ別売上シェアの円グラフ(食品30%・家電40%・衣料20%・その他10%)
  • ③商品別在庫の棒グラフ(5商品)
  • ④売上と在庫の散布図(ランダムデータ20件、numpy.random.seed(42) 使用)
  • 全体タイトルを suptitle で設定し、dashboard.png として保存する

【解答例】

import matplotlib.pyplot as plt
import matplotlib
import numpy as np

matplotlib.rcParams['font.family'] = 'IPAexGothic'

fig, axes = plt.subplots(2, 2, figsize=(12, 8))
fig.suptitle("販売ダッシュボード", fontsize=16)

# ①折れ線グラフ
months = range(1, 13)
sales = [120, 135, 150, 140, 160, 180, 200, 195, 170, 155, 140, 210]
axes[0, 0].plot(months, sales, marker="o")
axes[0, 0].set_title("月別売上")
axes[0, 0].set_xlabel("月")

# ②円グラフ
labels = ["食品", "家電", "衣料", "その他"]
sizes = [30, 40, 20, 10]
axes[0, 1].pie(sizes, labels=labels, autopct="%1.1f%%")
axes[0, 1].set_title("カテゴリ別シェア")

# ③棒グラフ
products = ["商品A", "商品B", "商品C", "商品D", "商品E"]
stock = [50, 30, 80, 20, 60]
axes[1, 0].bar(products, stock)
axes[1, 0].set_title("商品別在庫")

# ④散布図
np.random.seed(42)
x = np.random.randint(100, 500, 20)
y = np.random.randint(10, 100, 20)
axes[1, 1].scatter(x, y, alpha=0.7)
axes[1, 1].set_title("売上 vs 在庫")
axes[1, 1].set_xlabel("売上")
axes[1, 1].set_ylabel("在庫")

plt.tight_layout()
plt.savefig("dashboard.png")
print("dashboard.png を保存しました")

問題48:機械学習の基礎(線形回帰)

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • scikit-learn を使用して、住宅面積から価格を予測する線形回帰モデルを作成する
  • データ: 面積(㎡)= [30, 45, 60, 75, 90, 105, 120]、価格(万円)= [1500, 2200, 2800, 3500, 4100, 4800, 5500]
  • データを訓練データ(80%)とテストデータ(20%)に分割する(random_state=42
  • モデルを訓練し、テストデータでの平均絶対誤差(MAE)と R² スコアを表示する
  • 面積 80㎡ の予測価格を表示する

【期待する出力例】

MAE: 〇〇.〇〇万円
R²スコア: 0.99
80㎡の予測価格: 〇〇〇〇.〇〇万円

【解答例】

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score

X = np.array([30, 45, 60, 75, 90, 105, 120]).reshape(-1, 1)
y = np.array([1500, 2200, 2800, 3500, 4100, 4800, 5500])

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)
print(f"MAE: {mean_absolute_error(y_test, y_pred):.2f}万円")
print(f"R²スコア: {r2_score(y_test, y_pred):.2f}")

pred_80 = model.predict([[80]])[0]
print(f"80㎡の予測価格: {pred_80:.2f}万円")

問題49:パフォーマンス最適化

【問題】
以下の条件をすべて満たすプログラムを作成してください。

  • 1〜1,000,000 の素数をすべて求める関数を2種類実装する
    • find_primes_naive(n): 各数について2〜√nまで割り算するナイーブな方法
    • find_primes_sieve(n): エラトステネスの篩(numpy 使用可)
  • 両方の実行時間を計測して表示する
  • 両方の結果が一致することを assert で確認する
  • 改善率(何倍速いか)を表示する

【期待する出力例】

ナイーブ法: 3.5234秒 (78498個の素数)
篩法: 0.0512秒 (78498個の素数)
改善率: 68.8倍

【解答例】

import time
import math
import numpy as np

def find_primes_naive(n):
    primes = []
    for num in range(2, n + 1):
        is_prime = True
        for i in range(2, int(math.sqrt(num)) + 1):
            if num % i == 0:
                is_prime = False
                break
        if is_prime:
            primes.append(num)
    return primes

def find_primes_sieve(n):
    sieve = np.ones(n + 1, dtype=bool)
    sieve[0] = sieve[1] = False
    for i in range(2, int(math.sqrt(n)) + 1):
        if sieve[i]:
            sieve[i*i::i] = False
    return list(np.where(sieve)[0])

N = 1_000_000

start = time.time()
naive_result = find_primes_naive(N)
t_naive = time.time() - start

start = time.time()
sieve_result = find_primes_sieve(N)
t_sieve = time.time() - start

assert naive_result == sieve_result, "結果が一致しません"

print(f"ナイーブ法: {t_naive:.4f}秒 ({len(naive_result)}個の素数)")
print(f"篩法: {t_sieve:.4f}秒 ({len(sieve_result)}個の素数)")
print(f"改善率: {t_naive / t_sieve:.1f}倍")

問題50:総合プロジェクト — データ管理Webアプリ

【問題】
以下の条件をすべて満たす、Flaskを使ったタスク管理Webアプリケーションを作成してください。

  • バックエンド(Flask)
    • SQLiteを使ってタスクを永続化する(カラム: idtitledonecreated_at
    • REST API: GET /api/tasksPOST /api/tasksPUT /api/tasks/<id>DELETE /api/tasks/<id>
  • フロントエンド
    • Flask の render_template でHTMLを返し、JavaScriptの fetch APIでバックエンドと通信する
    • タスク一覧表示・追加・完了チェック・削除ができること
  • その他
    • ログ出力(loggingモジュール)を含める
    • 入力バリデーション(空のタスク名を拒否)を実装する

【解答例】

# app.py
import sqlite3
import logging
from datetime import datetime
from flask import Flask, jsonify, request, render_template_string, abort

logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

app = Flask(__name__)
DB = "tasks.db"

def get_db():
    conn = sqlite3.connect(DB)
    conn.row_factory = sqlite3.Row
    return conn

def init_db():
    with get_db() as conn:
        conn.execute("""CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            done INTEGER DEFAULT 0,
            created_at TEXT DEFAULT CURRENT_TIMESTAMP
        )""")

HTML = """
<!DOCTYPE html>
<html lang="ja"><head><meta charset="UTF-8">
<title>タスク管理</title>
<style>body{font-family:sans-serif;max-width:600px;margin:40px auto}
.done{text-decoration:line-through;color:#aaa}
button{cursor:pointer}</style>
</head><body>
<h1>📋 タスク管理アプリ</h1>
<input id="title" placeholder="タスクを入力..." style="width:70%">
<button onclick="addTask()">追加</button>
<ul id="list"></ul>
<script>
async function load(){
  const res = await fetch('/api/tasks');
  const tasks = await res.json();
  document.getElementById('list').innerHTML = tasks.map(t =>
    `<li><input type="checkbox" ${t.done?'checked':''} onchange="toggle(${t.id})">
     <span class="${t.done?'done':''}">${t.title}</span>
     <button onclick="del(${t.id})">削除</button></li>`
  ).join('');
}
async function addTask(){
  const title = document.getElementById('title').value.trim();
  if(!title) return alert('タスク名を入力してください');
  await fetch('/api/tasks',{method:'POST',headers:{'Content-Type':'application/json'},
    body:JSON.stringify({title})});
  document.getElementById('title').value='';
  load();
}
async function toggle(id){
  await fetch(`/api/tasks/${id}`,{method:'PUT'});
  load();
}
async function del(id){
  await fetch(`/api/tasks/${id}`,{method:'DELETE'});
  load();
}
load();
</script></body></html>
"""

@app.route("/")
def index():
    return HTML

@app.route("/api/tasks", methods=["GET"])
def get_tasks():
    with get_db() as conn:
        rows = conn.execute("SELECT * FROM tasks ORDER BY id DESC").fetchall()
    return jsonify([dict(r) for r in rows])

@app.route("/api/tasks", methods=["POST"])
def create_task():
    data = request.get_json()
    title = (data or {}).get("title", "").strip()
    if not title:
        abort(400, description="タスク名は必須です")
    with get_db() as conn:
        cur = conn.execute("INSERT INTO tasks (title) VALUES (?)", (title,))
        task_id = cur.lastrowid
        conn.commit()
    logger.info(f"タスク追加: {title}")
    return jsonify({"id": task_id, "title": title, "done": 0}), 201

@app.route("/api/tasks/<int:task_id>", methods=["PUT"])
def toggle_task(task_id):
    with get_db() as conn:
        conn.execute("UPDATE tasks SET done = 1 - done WHERE id=?", (task_id,))
        conn.commit()
    logger.info(f"タスク更新: id={task_id}")
    return jsonify({"status": "ok"})

@app.route("/api/tasks/<int:task_id>", methods=["DELETE"])
def delete_task(task_id):
    with get_db() as conn:
        conn.execute("DELETE FROM tasks WHERE id=?", (task_id,))
        conn.commit()
    logger.info(f"タスク削除: id={task_id}")
    return "", 204

if __name__ == "__main__":
    init_db()
    app.run(debug=False, port=5000)

まとめ

全50問、お疲れ様でした。各問題には具体的な入出力条件と解答例を掲載しました。解答例はあくまで一例です。同じ出力が得られれば、別のアプローチでも問題ありません。

初級をマスターしたら中級へ、中級が完了したら上級にチャレンジしてみてください。特に問題50の総合プロジェクトは、これまでの知識を総動員する内容になっています。