閉じる

Pythonのwith構文でファイルを安全に開く方法と基本例

ファイル入出力は身近で便利ですが、扱いを誤ると閉じ忘れや例外でのリソースリークにつながります。

Pythonのwith構文は、ファイルを安全に開き、確実に閉じるための標準的な方法です。

本稿では、with構文でファイルを安全に扱う理由と、基本から実用例、初心者がつまずきやすいポイントまでを丁寧に解説します。

Pythonのwith構文とは(ファイルを安全に開く理由)

コンテキストマネージャで自動で閉じる

仕組みの概要

Pythonのwithは「コンテキストマネージャ」という仕組みを使います。

ファイルオブジェクトはコンテキストマネージャとして振る舞い、withブロックに入るときに準備し、出るときに後片付けを行います。

この後片付けにファイルのclose()が含まれるため、閉じ忘れが起きません

実務的な利点

コードは短く読みやすくなり、レビューでも意図を理解しやすくなります。

可読性と安全性を同時に満たせるのがwithの大きな魅力です。

例外時でも安全(後片付けが確実)

例外が発生しても自動でクリーンアップ

ブロック内で例外が発生しても、withは必ず後片付けを実行します

一方、withを使わない場合、後片付けを確実にするにはtry ... finallyを自分で書く必要があります。

振る舞いの比較(概要)

観点with構文手動でclose()
閉じ忘れの可能性なしあり
例外に対する強さ強い(確実に閉じる)try … finallyが必要
コード量短い長くなりがち
可読性高い低下しやすい

open()とwith構文の関係

それぞれの役割

open()はファイルを開いてファイルオブジェクトを返す関数です。

withは、そのオブジェクトのライフサイクル(開始と終了)を管理します。

open()がファイルを「用意」し、withが「安全に使って片付ける」という関係です。

よくある誤解

withopen()の代わりではありません。

with open(...) as f:の形で併用するのが基本です。

with構文の基本(使い方と最小コード例)

with open() as f の基本形

最小のパターン

最小の使い方はwith open(..., mode, encoding) as f:という形です。

以下はテキストを書き込む最小例です。

Python
# 最小のwith構文の例: ファイルに1行書き込む
# ポイント:
# - mode="w" は新規作成または上書き
# - encoding="utf-8" を明示すると文字化けを防ぎやすい
with open("sample.txt", mode="w", encoding="utf-8") as f:
    f.write("こんにちは、with構文!\n")  # ファイルに1行書く

# withブロックを抜けると自動でclose()される
print("書き込み完了")
実行結果
書き込み完了

ブロックの範囲=ファイルの有効範囲

ブロックを出ると自動で閉じられる

ファイルが有効に使えるのはwithブロックの内部だけと考えましょう。

ブロックを出ると自動的に閉じられます。

Python
# デモ用: ファイルを用意
with open("sample.txt", "w", encoding="utf-8") as f:
    f.write("line\n")

# withの内外で f.closed の値を比較
with open("sample.txt", "r", encoding="utf-8") as f:
    print("inside closed? ->", f.closed)  # False (開いている)
# ここでは f はスコープに残るが、既に閉じられている
print("outside closed? ->", f.closed)     # True  (閉じている)
実行結果
inside closed? -> False
outside closed? -> True

close()は不要

try … finallyを書かなくてよい

with構文を使えばclose()を明示的に呼ぶ必要はありません

同等の安全性を手動で確保するにはtry ... finallyが必要です。

Python
# 手動で安全に閉じる(推奨しないが等価な書き方)
f = open("sample.txt", "r", encoding="utf-8")
try:
    text = f.read()
    print("手動:", len(text), "文字")
finally:
    f.close()  # ここを忘れると危険

# withで簡潔かつ安全に書く(推奨)
with open("sample.txt", "r", encoding="utf-8") as f:
    text = f.read()
    print("with:", len(text), "文字")
実行結果
手動: 5 文字
with: 5 文字

目的別のwith構文例(ファイル操作の基本)

テキストを読む(read)

全文を一度に読み込む

f.read()はファイルの全文を文字列として返します。

小さめのファイルに向いています。

Python
# デモ用: 読み取り対象のファイルを作成
with open("read_sample.txt", "w", encoding="utf-8") as f:
    f.write("1行目\n2行目\n3行目\n")

# with構文で全文を読む
with open("read_sample.txt", "r", encoding="utf-8") as f:
    text = f.read()  # ファイル全体を取得
print(text, end="")  # 末尾の改行を活かすためend=""に
実行結果
1行目
2行目
3行目

行ごとに読む

for line in fで行単位に読み取れます。

メモリ効率がよく、大きなファイルにも向きます。

Python
with open("read_sample.txt", "r", encoding="utf-8") as f:
    for idx, line in enumerate(f, start=1):
        print(f"{idx}:", line.strip())
実行結果
1: 1行目
2: 2行目
3: 3行目

テキストに書く(write)

1行ずつ追記または上書き

write()で文字列を書き込みます。

mode=”w”は既存ファイルを上書きし、mode="a"は末尾に追記します。

Python
lines = ["alpha", "beta", "gamma"]

# 上書き作成
with open("write_sample.txt", "w", encoding="utf-8") as f:
    for line in lines:
        f.write(line + "\n")  # 改行は手動で付ける

print("書き込み完了: write_sample.txt")
実行結果
書き込み完了: write_sample.txt

複数ファイルを同時に開く(カンマ区切り)

2つ以上を一度に管理

カンマで区切って複数のファイルを同時に開くことができます。

両方ともブロック終了時に自動で閉じられます。

Python
# デモ用: コピー元を用意
with open("source.txt", "w", encoding="utf-8") as s:
    s.write("copy me\nline2\n")

# 2つのファイルを同時に開き、行単位でコピー
with open("source.txt", "r", encoding="utf-8") as src, \
     open("dest.txt", "w", encoding="utf-8") as dst:
    for line in src:
        dst.write(line)

print("コピー完了: dest.txt に書き出しました")
実行結果
コピー完了: dest.txt に書き出しました

例外を補足する(try exceptと併用)

openの失敗を捕捉する

ファイルが存在しない場合など、open()自体が例外を送出します

このときはtryの中でwith open(...)を書きます。

Python
filename = "no_such_file.txt"

try:
    with open(filename, "r", encoding="utf-8") as f:
        data = f.read()
        print(data)
except FileNotFoundError as e:
    print("ファイルが見つかりません:", e.filename)
実行結果
ファイルが見つかりません: no_such_file.txt

読み取り中の失敗を捕捉する

withに入った後の処理で起こる例外は、ブロックの内側で捕捉します。

どちらの場合もファイルは必ず閉じられます

Python
# デモ用: 不正な変換を起こすケースを演出
with open("numbers.txt", "w", encoding="utf-8") as f:
    f.write("10\n20\nnot-a-number\n30\n")

# 行を整数に変換。失敗したら行番号付きで通知
try:
    with open("numbers.txt", "r", encoding="utf-8") as f:
        for i, line in enumerate(f, start=1):
            value = int(line.strip())  # ここでValueErrorになる可能性
            print("OK:", value)
except ValueError as e:
    print("整数に変換できない行があります:", e)
実行結果
OK: 10
OK: 20
整数に変換できない行があります: invalid literal for int() with base 10: 'not-a-number'

安全に使うコツ(初心者向けベストプラクティス)

encodingを明示する(utf-8)

文字化けを防ぐ基本設定

常にencoding="utf-8"を明示するのがおすすめです。

OSや環境によってはデフォルトのエンコーディングがUTF-8ではないことがあり、文字化けの原因になります。

Python
# UTF-8で書いてUTF-8で読む
with open("utf8_sample.txt", "w", encoding="utf-8") as f:
    f.write("あいうえお\n")

with open("utf8_sample.txt", "r", encoding="utf-8") as f:
    print("encoding:", f.encoding)
    print("content:", f.read().strip())
実行結果
encoding: UTF-8
content: あいうえお

パス操作はpathlibを使う(Path)

文字列連結より安全で可読

pathlib.Pathを使うと、OS差異を気にせずパス結合や作成ができます。

パスのバグを減らし、テストもしやすくなります

Python
from pathlib import Path

data_dir = Path("data")
data_dir.mkdir(exist_ok=True)  # フォルダがなければ作成

file_path = data_dir / "notes.txt"  # OSに依存しない結合
with file_path.open("w", encoding="utf-8") as f:
    f.write("pathlibで書いたテキスト\n")

print("作成したファイル:", file_path)  # data/notes.txt など
実行結果
作成したファイル: data/notes.txt

大きなファイルは逐次処理(iterで行単位)

メモリ効率よく処理する

大きなファイルではread()で全読み込みせず、for line in fで逐次処理しましょう。

必要な部分だけ読むのが基本です。

Python
# デモ用: 行数のあるファイルを用意
with open("big.txt", "w", encoding="utf-8") as f:
    for i in range(1, 6):
        f.write(f"{i}行目\n")

# 先頭3行だけプレビュー
with open("big.txt", "r", encoding="utf-8") as f:
    for i, line in enumerate(f, start=1):
        if i > 3:
            break
        print(line.strip())
実行結果
1行目
2行目
3行目

バイナリファイルでも使える(mode b)

画像や実行ファイルはバイナリモード

テキスト以外はrbwbで開きます

改行変換や文字コード処理を避け、バイト列をそのまま扱えます。

Python
# PNGのシグネチャ(先頭8バイト)を例にバイナリで読み書き
png_sig = bytes.fromhex("89504E470D0A1A0A")

# 書き込みはwb(バイナリ書き込み)
with open("sig.bin", "wb") as f:
    f.write(png_sig)

# 読み込みはrb(バイナリ読み込み)
with open("sig.bin", "rb") as f:
    head = f.read(8)  # 先頭8バイト
print("hex:", head.hex())
実行結果
hex: 89504e470d0a1a0a

まとめ

Pythonでファイルを安全に扱う最も簡単で確実な方法はwith open(...) as f:を使うことです。

これにより、例外の有無に関わらず自動でclose()が呼ばれ、閉じ忘れやリソースリークを防げます。

初心者の方は次の3点をまず徹底すると良いです。

1つ目はencoding="utf-8"を常に明示すること、2つ目はpathlib.Pathでパスを扱うこと、3つ目は大きなファイルをfor line in fで逐次処理することです。

さらに複数ファイルの同時オープンやtry ... exceptとの併用も、基本のパターンに沿えば自然に書けます。

日々のコードでwithを習慣化し、シンプルかつ堅牢なファイル操作を身につけていきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!