Python | ファイル操作など:プログラム構造の基本

Python
スポンサーリンク

概要(「読みやすく、壊れにくい」プログラム構造の土台を作る)

プログラム構造の基本は、役割ごとにコードを分けて、入口と出口を明確にし、外部資源(ファイル・フォルダ)を安全に扱い、失敗に備えることです。初心者は「関数で処理を分割」「if name == ‘main‘ で実行入口を定義」「with 文で後片付けを自動化」「例外を絞って受ける」の4本柱をまず身につけましょう。

ファイル操作に強い基本設計(入口・分割・後片付け)

実行入口を明確にする(if name == “main“)

スクリプトとして動かすときの「入口」をここに定義します。テストや再利用時に import しても、勝手に実行されないため安全です。

def main():
    # ここに「最上位の流れ」を書く
    print("start")

if __name__ == "__main__":
    main()
Python

関数で「ひと仕事」をまとめる(再利用・テストしやすい)

読み込み、加工、書き出しのような流れは、関数を分けると見通しが劇的に良くなります。引数と戻り値で「何を受け取り、何を返すか」を明確化します。

def load_lines(path: str) -> list[str]:
    with open(path, "r", encoding="utf-8") as f:
        return [line.rstrip("\n") for line in f]

def transform(xs: list[str]) -> list[str]:
    return [x.upper() for x in xs]

def save_lines(path: str, xs: list[str]) -> None:
    with open(path, "w", encoding="utf-8", newline="\n") as f:
        f.write("\n".join(xs) + "\n")
Python

with 文で外部資源の「後片付け」を自動化する

ファイルは開いたら必ず閉じる必要があります。with を使えば、例外が起きても確実に閉じられ、漏れがありません。

from pathlib import Path

def read_text(p: Path) -> str:
    with p.open("r", encoding="utf-8") as f:
        return f.read()
Python

例外を「必要な範囲」にだけ掛ける(握り過ぎない)

想定済みの失敗(存在しない・権限なし)は受け止め、未知の失敗は上位へ伝えます。ユーザー向けの簡潔なメッセージと、開発者向けの詳細ログを分けると運用が楽になります。

def load_safe(path: str) -> str | None:
    try:
        with open(path, "r", encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError:
        print("ファイルが見つかりません:", path)
        return None
Python

パス・配置・レイアウト(Path を軸に「安全に辿る」)

pathlib.Path を使って「文字列連結を卒業する」

OS差(/ と \)を気にせず、パス結合や作成を直感的に書けます。最初に「プロジェクトの基準パス」を決める習慣をつけましょう。

from pathlib import Path

ROOT = Path(__file__).resolve().parent
DATA = ROOT / "data"
OUT  = ROOT / "output"

def ensure_dirs() -> None:
    OUT.mkdir(parents=True, exist_ok=True)
Python

読み書きのショートカットで簡潔にする

read_text/write_text や read_bytes/write_bytes を活用すると、open の定型を減らせます。エンコーディングは原則 UTF-8 を明示します。

p = DATA / "input.txt"
q = OUT / "result.txt"
text = p.read_text(encoding="utf-8")
q.write_text(text.upper(), encoding="utf-8")
Python

設定・ログ・引数(外部化して「差し替えやすく」)

設定は JSON/ENV に外出し(コードと値を分離)

ハードコードすると変更に弱くなります。設定ファイルを読み込み、デフォルト値と上書きの仕組みを用意して柔軟にします。

import json
from pathlib import Path

def load_config(path: Path) -> dict:
    if not path.exists():
        return {"encoding": "utf-8", "newline": "\n"}
    return json.loads(path.read_text(encoding="utf-8"))
Python

ログで「何が起きたか」を残す(標準ライブラリで十分)

print でも良いですが、logging を使うとレベルや出力先の管理が楽です。ファイル操作は外部要因で失敗しやすいため記録が重要です。

import logging
logging.basicConfig(filename="app.log", level=logging.INFO)

def log_started() -> None:
    logging.info("app started")
Python

コマンドライン引数で「入力と出力」を選べるようにする

argparse を使うと、入力ファイルや出力先を起動時に差し替えられます。構造化されたツールへ一歩近づきます。

import argparse
from pathlib import Path

def parse_args() -> tuple[Path, Path]:
    ap = argparse.ArgumentParser()
    ap.add_argument("--in",  dest="inp", type=Path, required=True)
    ap.add_argument("--out", dest="out", type=Path, required=True)
    a = ap.parse_args()
    return a.inp, a.out
Python

安全な書き込み・誤上書き対策(成果物を守る)

一時ファイル→置き換えで「原子的」に保存する

途中で落ちても壊れたファイルが残らないように、テンポラリに書いてから置き換えます。重要なレポート・集計で有効です。

import os
from pathlib import Path

def atomic_write(path: Path, data: str) -> None:
    tmp = path.with_suffix(path.suffix + ".tmp")
    tmp.write_text(data, encoding="utf-8")
    os.replace(tmp, path)
Python

誤上書きを避けるために「新規のみ」モードを使う

“x” モードで開けば既存なら例外になり、成果物を守れます。ポリシーに沿ったメッセージを出しましょう。

def save_new(path: Path, text: str) -> bool:
    try:
        with path.open("x", encoding="utf-8", newline="\n") as f:
            f.write(text)
        return True
    except FileExistsError:
        print("既存のため作成しません:", path)
        return False
Python

ひな形(小さなツールの「実務で通る」構造)

最小でも「入口・引数・処理分割・安全化」を入れる

import argparse
from pathlib import Path

def load_lines(p: Path) -> list[str]:
    with p.open("r", encoding="utf-8") as f:
        return [line.rstrip("\n") for line in f]

def transform(xs: list[str]) -> list[str]:
    return [x.upper() for x in xs]

def save_lines(p: Path, xs: list[str]) -> None:
    p.parent.mkdir(parents=True, exist_ok=True)
    with p.open("w", encoding="utf-8", newline="\n") as f:
        f.write("\n".join(xs) + "\n")

def parse_args() -> tuple[Path, Path]:
    ap = argparse.ArgumentParser(description="Uppercase converter")
    ap.add_argument("--in",  dest="inp", type=Path, required=True)
    ap.add_argument("--out", dest="out", type=Path, required=True)
    a = ap.parse_args()
    return a.inp, a.out

def main() -> None:
    inp, out = parse_args()
    try:
        lines = load_lines(inp)
    except FileNotFoundError:
        print("入力が見つかりません:", inp)
        return
    result = transform(lines)
    save_lines(out, result)
    print("done:", out)

if __name__ == "__main__":
    main()
Python

この構造なら、入口が明確で、関数に分割され、例外で失敗を伝え、フォルダを自動作成し、改行とエンコーディングを明示して安定します。小さいのに「現場で通る」品質に近づきます。

まとめ

プログラム構造の基本は、入口の明確化(if name == “main“)、関数分割で見通しと再利用性を高め、with 文で後片付けを自動化し、例外を必要十分に扱うこと。パスは pathlib.Path を使い、プロジェクトの基準パスから辿る。設定・ログ・引数を外部化して差し替えやすくし、書き込みは原子的保存や新規作成モードで成果物を守る。まずはこの型(ひな形)を真似し、あなたの処理を中に差し替えていけば、初心者でも短いコードで、安定して運用できるファイル操作プログラムを作れます。

タイトルとURLをコピーしました