Python環境を起動中... 初回のみ数秒かかります
Lesson 16 / 20

ファイル入出力

このレッスンで学ぶこと

  • open() でファイルを読み書きできる
  • with 文でファイルを安全に開閉できる
  • 行単位・一括読み込みを使い分けられる
  • csv モジュールでCSVを辞書として読み込める

1. ファイルの書き込みと読み込み

open(ファイル名, モード) でファイルを開きます。 モードは "w"(書き込み), "r"(読み込み), "a"(追記)です。 with 文を使うと、ブロックを抜けた時点で自動的にファイルが閉じられます。

sample_1.py
Ctrl+Enter
出力

💡 with文の重要性: with open(...) as f: を使うと、例外が発生してもファイルが確実に閉じられます。f.close() を書き忘れるバグを防ぐためにも、常に with を使う習慣をつけましょう。

📋 "w" と "a" の使い分け: どちらも f.write() で書き込めますが、ファイルを開いた瞬間の動作が異なります。

  • "w"(write)— ファイルを新規作成または上書きします。既存のファイルがあれば内容が全て消えます。
  • "a"(append)— ファイルが存在すれば末尾に追記します。存在しなければ新規作成します。

患者ログを日々追加していく場合は "a"、毎回新しいデータで置き換えるレポート出力には "w" が適しています。

2. 行単位の読み込み

f.read() はファイル全体を1つの文字列として読みます。一方、大きなファイルでは行単位で処理する方が効率的です。

sample_2.py
Ctrl+Enter
出力

💡 文字列ログから数値を取り出すには:

split() を連続して使うと、フォーマットが決まったログから数値部分を抽出できます。

line = "2026-05-01 15:00, SpO2=93%, HR=110, BP=145/95"

# "SpO2=" の後ろを取得 → "93%, HR=110, BP=145/95"
# さらに "%" の前を取得 → "93" → int() で数値化
spo2_val = int(line.split("SpO2=")[1].split("%")[0])  # 93

# "HR=" の後ろを取得 → "110, BP=145/95"
# さらに "," の前を取得 → "110" → int() で数値化
hr_val = int(line.split("HR=")[1].split(",")[0])       # 110

数値条件の判定には必ず int() に変換してから比較しましょう。より複雑なパターンには import re(正規表現、L18)、構造化データには後述の CSV 処理 が適しています。

3. CSV の読み書き

csv モジュールを使うと、CSV形式のデータを簡単に扱えます。 csv.DictWriter で辞書リストをCSVに書き出し、 csv.DictReader で読み込むとヘッダーをキーとした辞書として扱えます。

sample_3.py
Ctrl+Enter
出力

📋 CSV 書き込みで使う3つのポイント:

  • newline=""open() に渡す引数。Windows では改行コードが二重になる問題を防ぐために必要です。CSV ファイルを書くときは常に指定する習慣をつけましょう。
  • writer.writeheader()fieldnames で指定した列名を1行目(ヘッダー行)として書き込みます。
  • writer.writerows(データリスト) — 辞書のリストをまとめて書き込みます。for row in records: writer.writerow(row) と同じ意味ですが1行で書けます。

🚀 実務では Pandas を使うことが多い

CSV や Excel を扱う実務・AI 開発では Pandasimport pandas as pd)というライブラリがよく使われます。

import pandas as pd

df = pd.read_csv("patients.csv")        # 1行で読み込み
print(df["spo2"].mean())                 # 平均も1行
df[df["spo2"] < 95]                      # 条件フィルタも直感的

Pandas は標準ライブラリではないため別途インストールが必要ですが(pip install pandas)、このコース(Pyodide環境)ではそのまま使えます(実行に時間かかるため注意)。今は csv モジュールでファイル操作の基礎を押さえておけば、Pandas にスムーズに移行できます。

4. os.path でファイルパスを操作する

os.path モジュールを使うと、ファイルの存在確認・パス結合・拡張子取得などが OS(Windows/Mac/Linux)に依存せず書けます。

sample_4.py
Ctrl+Enter
出力

💡 医療AI文脈: DICOMファイルやCSVデータセットを読み込む際、os.path.join() でパスを組み立て、os.path.exists() で存在確認してから開くのがベストプラクティスです。

5. 練習問題

問題 1

患者データをファイルに書き込む

患者名・年齢・診断名のリストを /tmp/patients.txt に書き込み、その後読み込んで表示してください。各行のフォーマットは「名前,年齢,診断名」です。

exercise_1.py
出力
ヒントを見る(答え+解説)
patients = [
    ("田中太郎", 45, "高血圧"),
    ("山田花子", 62, "糖尿病"),
    ("佐藤次郎", 33, "肺炎"),
]

filename = "/tmp/patients.txt"

with open(filename, "w", encoding="utf-8") as f:
    for p in patients:
        f.write(f"{p[0]},{p[1]},{p[2]}\n")

print("=== 患者ファイル内容 ===")
with open(filename, "r", encoding="utf-8") as f:
    print(f.read())
# → 田中太郎,45,高血圧
# → 山田花子,62,糖尿病
# → 佐藤次郎,33,肺炎

with open() 構文はファイルを自動でクローズします。書き込みは "w"、読み込みは "r" モードを使い、日本語を含む場合は encoding="utf-8" を指定しましょう。

問題 2

CSVから検査値を読み込んで統計表示

CSVファイルに血糖値データを書き込み、csv.DictReader で読み込んで平均・最大・最小を表示してください。

exercise_2.py
出力
ヒントを見る(答え+解説)
import csv

csv_file = "/tmp/glucose.csv"
records = [
    {"date": "2026-05-01", "time": "朝", "glucose": 95},
    {"date": "2026-05-01", "time": "昼", "glucose": 140},
    {"date": "2026-05-01", "time": "夕", "glucose": 165},
    {"date": "2026-05-02", "time": "朝", "glucose": 102},
    {"date": "2026-05-02", "time": "昼", "glucose": 155},
]

with open(csv_file, "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["date", "time", "glucose"])
    writer.writeheader()
    writer.writerows(records)

with open(csv_file, "r", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

values = [int(row["glucose"]) for row in rows]
print(f"平均: {sum(values)/len(values):.1f} mg/dL")
print(f"最大: {max(values)} mg/dL")
print(f"最小: {min(values)} mg/dL")
# → 平均: 131.4 mg/dL / 最大: 165 mg/dL / 最小: 95 mg/dL

穴埋め箇所は values = [int(row["glucose"]) for row in rows] の1行だけです。

テンプレートの書き込み部分の解説:

  • newline="" — Windows 環境で改行コードが二重になるのを防ぐ。CSV 書き込み時の定型句です。
  • writer.writeheader()fieldnames に渡した列名をCSVの1行目(ヘッダー行)として書き込みます。
  • writer.writerows(records) — 辞書のリストを一括で書き込みます(for row in records: writer.writerow(row) と同じ)。

csv.DictReader は各行を列名→値の辞書として読み込みます。CSVの値はすべて文字列なので、数値計算には必ず int()float() で変換が必要です。

問題 3

ファイルの存在確認と安全な読み込み

os.path.exists() でファイルが存在するか確認してから読み込む関数 safe_read(filepath) を作ってください。存在しない場合は None を返します。

exercise_3.py
出力
ヒントを見る(答え+解説)
import os

def safe_read(filepath):
    """ファイルが存在すれば内容を返し、なければNoneを返す"""
    if not os.path.exists(filepath):
        print(f"ファイルが見つかりません: {filepath}")
        return None
    with open(filepath, "r", encoding="utf-8") as f:
        return f.read()

with open("/tmp/test.txt", "w") as f:
    f.write("テストデータ\n血糖値: 120 mg/dL")

result = safe_read("/tmp/test.txt")
print("存在するファイル:", result)

result2 = safe_read("/tmp/no_such_file.txt")
print("存在しないファイル:", result2)
# → 存在するファイル: テストデータ\n血糖値: 120 mg/dL
# → ファイルが見つかりません: /tmp/no_such_file.txt
# → 存在しないファイル: None

os.path.exists() でファイルの存在を確認してから開くことでエラーを防ぎます。None を返すことで呼び出し側が「ファイルなし」を判断できる、安全な設計パターンです。

まとめ

このレッスンのポイント

  • with open(path, mode, encoding="utf-8") as f: でファイルを安全に開く
  • モード: "r"(読込), "w"(書込・上書き), "a"(追記)
  • f.read() で全体読込、for line in f: で行単位
  • csv.DictWriter / csv.DictReader で辞書形式のCSV処理
  • os.path.join() でパス結合、os.path.exists() で存在確認

自由に試してみましょう:

free_practice.py
Ctrl+Enter
出力

完了するとトップページに進捗が表示されます