10 / 90

Day 10: ファイル、パス、エンコーディング

壊れやすいファイル読み取りを予測可能なプログラムに変える:パスをスクリプトに固定し、エンコーディングを明示し、with で資源を解放し、証拠からファイル不在と不正内容を診断する。 Retrieval and lower-new-content review are part of the 480-minute ledger.

Self-Directed Learning & Python 480 active minutes (8 hours focused study)
01 120 分

パス、エンコーディング、安全なファイル読み取り

支援は、予測と観察した証拠を記録した後にのみ許可される。

Prerequisites

前のアクティビティを完了していること。行き詰まったら、記載の回復リンクを使う。

Learning Objective

with ブロック内で UTF-8 エンコーディングを明示してテキストファイルを読み、空でない行を数える。実行前に行数を予測し、相対パスがカレントワーキングディレクトリに依存する理由を説明する。

Instructions

参照資料: この活動に割り当てられた既存の読解・練習時間内で、Automate the Boring Stuff with Python, 3rd edition の Chapter 10; Practice Questions; Appendix B answers を参照し、ローカル課題とのつながりを一つ自分の言葉で説明する。既存の演習と合格基準は維持し、外部資料が開けない場合は本コース独自の説明を使う。新しいディレクトリに notes.txt を作り、ちょうど3行 alpha、beta、gamma を書く。open("notes.txt") のような相対パスは、スクリプトのあるフォルダではなく Path.cwd() 基準で解決される。ファイルオブジェクトを反復すると1行ずつ得られ、各行は末尾の "\n" を保持する。ただし最終行だけは例外になりうる:ファイルが改行で終わっていなければ最終行に改行は付かない("alpha\nbeta\ngamma" と書いたファイルの最終行は 'gamma')。line.strip() がその改行と前後の空白を取り除くので、空行かどうかは strip() で判定できる。with ブロックは定義済みのクリーンアップで、読み取りが例外を起こしてもファイルを閉じる。

Practice & Prediction Log

count = 0
with open("notes.txt", encoding="utf-8") as f:
for line in f:
if line.strip():
count += 1
print(count, f.closed)
実行前に、出力される1行を正確に書き出し、2つの値がそれぞれなぜそうなるかを説明する。notes.txt が改行で終わっていなかったら結果は変わるか?

Independent Mastery Criterion

予測が観察した出力と一致し、相対パスが Path.cwd() 基準で解決されると述べ、with ブロック終了後のファイルオブジェクトの closed 状態(f.closed)を示せる。

Authoritative Source Resources & Provenance

linking Copyright Al Sweigart; edition-specific reuse terms unverified linking only; no reproduction

Automate the Boring Stuff with Python, 3rd edition

著者・提供機関: Al Sweigart | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Chapter 10; Practice Questions; Appendix B answers

検証バージョンと日付: Public edition checked 2026-11-01; moving pages may change

選定理由:

Beginner teaching and answer-keyed practice before checking exact semantics in the Python reference; selected chapters only, not the book's entire automation stack.

ソース前提知識:

No prior programming required for Chapter 1; later chapters assume its basic Python concepts.

安全フォールバック(オフライン回復性):

Use the original localized explanations, exercises and checks already present in this activity; no external account or purchase is required for that fallback.

比較対象候補リソースと選定評価 (2)
The Python Tutorial ↗ compared_alternative [PSF License Version 2]

Guided Python syntax but assumes programming familiarity; paired with the beginner text rather than used as its replacement.

MIT OCW 6.0001 ↗ compared_alternative [CC BY-NC-SA 4.0]

Lectures and problem sets teach a broader CS1 course; the book offers shorter text-first entry and an answer appendix.

linking PSF License Version 2

The Python Tutorial: Input and Output

著者・提供機関: Python Software Foundation | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Section 7.2 (Reading and Writing Files)

検証バージョンと日付: Python 3.12 documentation; verified 2026-10-30

選定理由:

Primary reference for open(), explicit encodings, and the with statement as guaranteed cleanup.

ソース前提知識:

安全フォールバック(オフライン回復性):

The lesson explains all required behavior locally and can be completed offline; help(open) also works in the interpreter.

比較対象候補リソースと選定評価 (2)
Real Python: Reading and Writing Files ↗ compared_alternative [Proprietary (free and paid tiers)]

Friendly walkthrough, but it is a secondary tutorial with mixed access tiers rather than the normative language reference.

io — Core tools for working with streams ↗ compared_alternative [PSF License Version 2]

Stream-layer reference for advanced cases; the tutorial chapter covers the open()/with patterns the drills require.

02 120 分

コードを直す前にファイル不在を診断する

支援は、予測と観察した証拠を記録した後にのみ許可される。

Prerequisites

前のアクティビティを完了していること。行き詰まったら、記載の回復リンクを使う。

Learning Objective

open("data/notes.txt") が投げる FileNotFoundError を再現し、コードを触る前に Path.exists() と Path.cwd() の証拠で、原因がファイル不在かワーキングディレクトリ違いかを分類する。

Instructions

使い捨てのフィクスチャだけで作業する:このアクティビティのスクリプトは、新しい一時ディレクトリの中に project/(reader.py と data/notes.txt を含む)と空の兄弟フォルダ outside/ を作り、終了時に削除する。そのため結果は、ホームディレクトリや実際のプロジェクトにたまたま何があるかに左右されない。メッセージ [Errno 2] No such file or directory: 'data/notes.txt' は、相対パスがカレントワーキングディレクトリから解決できなかったことだけを示し、2つの原因を区別できない。まず証拠を集める:Path.cwd() とスクリプトのフォルダを比較し、Path("data/notes.txt").exists()(cwd 基準)を評価し、BASE = Path(__file__).resolve().parent として (BASE / "data" / "notes.txt").exists()(スクリプト基準)を評価する。固定したパスは存在するのに相対パスが存在しないなら、原因はワーキングディレクトリ:open(BASE / "data" / "notes.txt", encoding="utf-8") とする。固定したパスも存在しないなら、フィクスチャは本当に無く、作成か復元が必要で、コードを変えても解決しない。

Practice & Prediction Log

このスクリプトを任意のディレクトリから実行する。使い捨てのフィクスチャを作り、未修正の reader.py(相対パス data/notes.txt を開く)を、project フォルダを cwd にして1回、outside/ を cwd にして1回実行する。実行前に、両方の実行の終了コードと表示される全行を予測する。その後、証拠から原因を分類し、カウント処理を書き直さずに reader.py への最小の修正を書く。

import subprocess
import sys
import tempfile
from pathlib import Path

READER = (
"from pathlib import Path\n"
"print('cwd is project:', Path.cwd() == Path(__file__).resolve().parent)\n"
"print('exists:', Path('data/notes.txt').exists())\n"
"with open('data/notes.txt', encoding='utf-8') as f:\n"
" print('lines:', sum(1 for line in f if line.strip()))\n"
)

with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp).resolve()
project = root / "project"
outside = root / "outside"
(project / "data").mkdir(parents=True)
outside.mkdir()
(project / "data" / "notes.txt").write_text("alpha\nbeta\ngamma\n", encoding="utf-8")
(project / "reader.py").write_text(READER, encoding="utf-8")
for label, cwd in [("project", project), ("outside", outside)]:
run = subprocess.run([sys.executable, str(project / "reader.py")],
cwd=cwd, capture_output=True, text=True)
print(f"[{label}] exit={run.returncode}")
print(run.stdout, end="")
if run.stderr:
print(run.stderr.strip().splitlines()[-1])

Independent Mastery Criterion

ログに2つの原因のどちらが当てはまったか、その証拠となる cwd/exists() の値、そしてリーダーを書き直すのでなく最小の修正(パス固定かファイル復元)を適用したことが記録されている。

Authoritative Source Resources & Provenance

linking PSF License Version 2

Python Standard Library: Built-in Exceptions

著者・提供機関: Python Software Foundation | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Concrete exceptions and Exception hierarchy

検証バージョンと日付: Python 3.12 documentation; verified 2026-10-30

選定理由:

Normative reference for FileNotFoundError attributes such as filename and errno used in the diagnosis drill.

ソース前提知識:

安全フォールバック(オフライン回復性):

The exercise reproduces FileNotFoundError locally, so the evidence exists even without the reference page.

比較対象候補リソースと選定評価 (2)
W3Schools Python Exceptions ↗ compared_rejected_for_day10 [Proprietary]

Beginner-friendly but not normative; its simplified hierarchy omits the OSError attributes the drill inspects.

The Python Tutorial: Errors and Exceptions ↗ compared_alternative [PSF License Version 2]

Friendlier first-pass narrative; the library reference was selected for the normative hierarchy the exercises name directly.

linking PSF License Version 2

Python Standard Library: pathlib

著者・提供機関: Python Software Foundation | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Path.exists, Path.cwd, and anchoring paths to __file__

検証バージョンと日付: Python 3.12 documentation; verified 2026-10-30

選定理由:

Normative reference for exists()/cwd() evidence that separates an absent file from a wrong working directory.

ソース前提知識:

安全フォールバック(オフライン回復性):

Path.exists() and Path.cwd() are exercised directly in the local drill, so no online page is required.

比較対象候補リソースと選定評価 (2)
os.path documentation ↗ compared_alternative [PSF License Version 2]

Functionally equivalent for exists() checks, but pathlib keeps the beginner syntax object-oriented and consistent across activities.

shutil — High-level file operations ↗ compared_alternative [PSF License Version 2]

Covers copying and moving whole trees rather than path modeling; pathlib remains the right reference for the filesystem checks these days rehearse.

03 120 分

不正な内容:スキップ報告つきの寛容なパース

支援は、予測と観察した証拠を記録した後にのみ許可される。

Prerequisites

前のアクティビティを完了していること。行き詰まったら、記載の回復リンクを使う。

Learning Objective

1行だけ不正なスコアファイルをパースし、スキップした行番号をすべて記録して処理を続ける。UnicodeDecodeError(バイトを誤ったエンコーディングでデコード)と ValueError(テキストは正しいが値が不正)を区別する。

Instructions

行は ana,7 の形。int("x9") は ValueError: invalid literal for int() with base 10: 'x9' を投げる。int(raw) の呼び出しだけを try/except ValueError で囲み、行番号を skipped リストに追加し、パースが成功したときだけスコアを保存する。デコードの問題は別種の失敗である:バイト列 b'caf\xe9'(Latin-1 で保存した café)は有効な UTF-8 ではないので、b'caf\xe9'.decode("utf-8") は UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3: unexpected end of data を投げる。これを「Latin-1 のファイルは必ず UTF-8 として失敗する」と一般化してはいけない:ASCII だけのファイルはどちらでも同じ結果にデコードされ、両方のエンコーディングで有効だが別のテキストになるバイト列もある(b'caf\xc3\xa9' は UTF-8 では café、Latin-1 では café)。つまりデコードが成功しても、エンコーディングが正しい証明にはならない。直し方は本当のエンコーディングを指定すること——デコードできないバイトを黙って捨てて問題を隠す errors="ignore" は使わない。

Practice & Prediction Log

行 ana,7 / bo,x9 / cy,5(1行1件)に対して、実行前に寛容なリーダーの結果を予測する:どの行が scores に入り、どの行番号が skipped に入るか。その後、この完全なプログラムを任意のディレクトリから実行する。プログラムは自前の scores.txt フィクスチャを一時ディレクトリに書き込み(終了後に削除される)、ループの前に scores と skipped を定義している。try ブロックは int(raw) だけに限定し、パースが成功した後でのみスコアを保存する。

import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "scores.txt"
path.write_text("ana,7\nbo,x9\ncy,5\n", encoding="utf-8")
scores = {}
skipped = []
with open(path, encoding="utf-8") as f:
for lineno, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
name, _, raw = line.rpartition(",")
try:
score = int(raw)
except ValueError:
skipped.append(lineno)
continue
scores[name] = score
print(scores, skipped)

Independent Mastery Criterion

有効な行がすべて処理され、スキップした行番号が記録され、2種類の失敗を正しく名付けられる:UnicodeDecodeError は宣言したエンコーディングを直せ、ValueError はその行の内容が不正だという意味。

Authoritative Source Resources & Provenance

linking PSF License Version 2

Python Unicode HOWTO

著者・提供機関: Python Software Foundation | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Encodings, decoding, and the causes of UnicodeDecodeError

検証バージョンと日付: Python 3.12 documentation; verified 2026-10-30

選定理由:

Primary explanation of byte-to-text decoding so learners fix the encoding instead of hiding errors.

ソース前提知識:

安全フォールバック(オフライン回復性):

The fixture bytes that trigger UnicodeDecodeError ship with the exercise, so the behavior is observable offline.

比較対象候補リソースと選定評価 (3)

Established motivation for encodings, but redistribution rights are unclear and it does not document Python's decode behavior.

Unicode Standard (unicode.org) official documentation ↗ compared_alternative [Unicode License Agreement / Terms of Use]

Exhaustive normative standard but far too deep for a first contact; the Python HOWTO teaches the same code point/encoding distinction in executable form.

Strong motivation and history but pre-Python-3 and not runnable; retained as optional background reading only.

04 120 分

独立したファイル集計と回復計画

独立習得チェック(AI の支援なし)。

Prerequisites

前のアクティビティを完了していること。行き詰まったら、記載の回復リンクを使う。

Learning Objective

閉巻で summarize_scores(path) を実装し、{"scores": {name: 最高点}, "skipped": [行番号], "missing": bool} を返す。有効なファイル、不正行を含むファイル、存在しないファイルの3つをクラッシュせず処理する。

Instructions

コーディング前に3つのフィクスチャの結果をすべて予測し、チェック中は答えや AI を見ない。行き詰まったときの回復リンク:ファイル不在は day-10-act-02、不正行は day-10-act-03。

Practice & Prediction Log

期待される契約(他のファイルが干渉しないよう、フィクスチャは新しい一時ディレクトリに作る。例:tempfile.TemporaryDirectory()):ana,7 / bo,9 / ana,8 を含む s1.txt は {'scores': {'ana': 8, 'bo': 9}, 'skipped': [], 'missing': False} を返す(ana は8が7に勝つ)。ana,7 / bo,x9 / cy,5 を含む s2.txt は {'scores': {'ana': 7, 'cy': 5}, 'skipped': [2], 'missing': False} を返す(2行目が不正)。その一時ディレクトリ内の一度も作られていないパス(例:missing.txt)は、例外を投げず {'scores': {}, 'skipped': [], 'missing': True} を返す。

Independent Mastery Criterion

独力で3つのフィクスチャが予測どおりの辞書を正確に返し、不正行が行番号で報告され、存在しないファイルが traceback ではなく missing フラグを返す。

Authoritative Source Resources & Provenance

linking PSF License Version 2

The Python Tutorial: Input and Output

著者・提供機関: Python Software Foundation | オリジナル出所URL ↗

該当セクション・タイムスタンプ: Section 7.2 (Reading and Writing Files)

検証バージョンと日付: Python 3.12 documentation; verified 2026-10-30

選定理由:

Primary reference retained for the independent file-processing check.

ソース前提知識:

安全フォールバック(オフライン回復性):

The assessment runs entirely on local fixtures and the installed interpreter.

比較対象候補リソースと選定評価 (2)
Real Python: Reading and Writing Files ↗ compared_alternative [Proprietary (free and paid tiers)]

Supplementary only; the assessment targets behavior, not tutorial recall.

io — Core tools for working with streams ↗ compared_alternative [PSF License Version 2]

Stream-layer reference for advanced cases; the tutorial chapter covers the open()/with patterns the drills require.