Developer

【Python独学】with~as構文を使ったファイルの操作
2021.03.31
Lv1

【Python独学】with~as構文を使ったファイルの操作

前回、Pythonでテキストファイルを扱いました。
今回は、テキストファイルを開く際のopen関数まわりについて、+αをみていきましょう。

  • with~as構文を使おう
  • open関数の引数

with~as構文を使おう

前回は、テキストファイルをPythonで扱う方法について紹介しました。
基本的には、

・open関数でファイルを開く
・何らかの処理をする
・close関数でファイルを閉じる

というのがPythonでファイルを扱う際の流れになります。
close関数は、open関数で取得したファイルを閉じます。
この際、close関数を記述し忘れると、ファイルがプログラム上に読み込まれたまま、閉じられないことになります。
前回あげたサンプルのような短いプログラムでは、ファイルを扱うタイミングが
ファイルを閉じる = プログラムの終了
となっているため、あまり問題は起きません。
ですが、読み込みだけでなく書き込みの動作をプログラム上で行うようになったり、
Pythonを用いたシステムが作成したファイルを同システムや他のプログラムがあとから使おうとした際に、
閉じられていないためにファイルへのアクセス権を得られなかったりする場合があります。

そういった動作が起きるのを防ぐためにclose関数を記載することが大切なのですが…
複雑なプログラムになったり例外処理等を盛り込んでいくと、どこでファイルをcloseするべきなのかわかりづらかったり、closeを書き忘れてしまうケースが起こります。
なので、Pythonではcloseを明示的に記述しなくてもよい構文が用意されています。
それが、with~as構文です。

with~as構文について

open関数でファイルを開く際、with~asを使用することで、closeを明示的に記述しなくても
処理が終わった時点でファイルを閉じてくれるようになります。
以下のように記述します。

with open(file, mode) as 変数:
   #何らかの処理

asの後ろで宣言している変数に、openで取得したファイルオブジェクトが代入される形になります。

このようにwith~asを使うと、以下のようにopen関数を記述した際と同じ処理になります。

変数 = open(file, mode)
   #何らかの処理
変数.close()

with~asを使えば、close関数を書き忘れることはなくなるわけですね。

また、のちの記事で取り上げる予定ですが、ファイルを扱う操作には例外処理を合わせて書くことが非常に多いです。
ファイルが存在しない、ファイルへのアクセス権を得られない、など例外が発生しやすいからですね。
これはPythonの公式ドキュメントでも触れられていることなのですが、with~asのメリットの1つとして、
「withを使うと処理中に例外が発生しても必ず最後にファイルを閉じることができる」
というものもあります。

では、前回の記事で扱ったサンプルをwith~asで書き直してみましょう。
前回のものがこちら。

f = open("sample.txt")

lines = f.read()          ### fの内容をreadで読み込み、linesに代入している

print(lines)

file1.close()

openでファイルを開き、readで内容を読み取り、closeで閉じています。
これをwith~asを使って記述すると、以下のようになります。

with open("sample.txt") as f:
	
	lines = f.read()
	
	print(lines)
C:\Python> python 14-2_1.py
Hello Python!

YAH YAH YAH

Goodbye Python

文量が減ったり、見やすくなったりという効果はそれほどですが、closeを書かなくても確実に
ファイルが閉じられるという安心感がありますね。


open関数の引数

さて、前回今回と引き続きopen関数でファイルを扱ってきました。
open関数の基本的な書き方は以前紹介したとおりですが、引数は以下のようになります。

open関数

open(file, mode=’r’, buffering=-1, encoding=None,
errors=None, newline=None, closefd=True, opener=None)

file:開くファイルのファイル名またはパス
mode:ファイルを開く際のモードを指定 デフォルト値は’r’
buffering:バッファリングの方法の指定 0は無効、1は行単位のバッファリング
encoding:テキストファイルで使用するエンコーディングを指定
errors:テキストファイルの読み書きの際エンコードなどに失敗した際の対応を指定
newline:テキストファイルの読み書きの際の改行コードの扱い方を指定
closefd:fileにファイル名ではなくファイル記述子が与えられた際の動作を指定 デフォルトはTrue
opener:ファイルのオープンに使用する呼び出せるオブジェクトを別途指定

上記のように引数はいくつか種類がありますが、実際によく使われるものであり覚えておくべきものとしては
modeが挙げられます。

open関数のモード

open関数では、ファイルを開く際にどのモードで開くかを引数modeで指定することができます。
デフォルトは’r’で、テキストモードで読み込み用に開く動作をします。

引数として与えられる値は以下のとおりです。
・’r’:ファイルを読み込み用として開く
・’w’:ファイルを書き込み用として開く
・’a’:ファイルを追記用として開く
・’x’:ファイルを新規に作成し、書き込み用として開く 既に同名ファイルがある場合はエラーを返す
・’b’:ファイルをバイナリモードで開く r,w,a,xと合わせて使う
・’t’:ファイルをテキストモードで開く r,w,a,xと合わせて使う
・’+’:ファイルを更新用に開く r,w,a,xと合わせて使う

r,w,a,xの4つについては、どれか1つを指定します。(ファイルの開き方を既定しているので、複数は使えません)
b,tの2つは、上記の4つとセットで指定します。
(bのバイナリモードについては今回は割愛させていただきます。)

前回の記事であげたサンプルのように、引数modeを省略した場合は’rt’を指定したのと同じ状態になります。
(テキストモードで読み込み専用)

with open("sample.txt", 'rt') as file1:
	
	lines = file1.read()
	
	print(lines)
C:\Python> python 14-2_2.py
Hello Python!

YAH YAH YAH

Goodbye Python

wとa、xはファイルへの書き込みを行います。これらのモードで開いた際は読み込みは行なえません。

with open("sample.txt", 'w') as file1:  ### wで書き込み用で開く
	
	lines = file1.read()                ### 書き込み用で開いたファイルを読み込もうとしている
	
	print(lines)
C:\Python> python 14-2_3.py
Traceback (most recent call last):
File “14-2_3.py”, line 3, in <module>
lines = file1.read()
io.UnsupportedOperation: not readable

「not readable」と表示されていることからわかるように、各書き込み用のモードでは読み取りはできません。
書き込みについてのメソッドを含めた説明は、次回以降の記事でみていきます。

w、aの2つのモードはどちらも書き込み用ではありますが、ファイルを開いた際の挙動が大きく異なります。
wは、指定したファイルが存在すればそれを開き、存在しなければファイルを作成します。
また、既存のファイルを開いた場合は内容を全て上書きします。つまり既存の内容は全て削除されることになります。
aは、w同様にファイルを開きますが、開いた時点でのファイルオブジェクトのファイル位置(内容の読み込み位置)を
ファイルの末尾とします。その状態で書き込みを行うと、ファイルの末尾から書き込みを行う、つまり追記になります。

xも同じく書き込み用でファイルを開きますが、既存ファイルではなく新規ファイルを指定します。
ファイル名に新しく作成するファイル名を指定し、書き込み用で開きます。
既存のファイルと同じファイル名を指定した場合はエラーになります。

w+,a+,x+とした場合は、読み込みと書き込みの両方が可能になります。


まとめ

・with~as構文を使うことで開いたファイルを確実に閉じることができる
・open関数にはいくつかの引数があり、modeでファイルのモードを指定する
・openのモードには、読み込み用、書き込み用、追記用などいくつかのモードが存在する


確認問題

以下の文章の空欄を埋めてみましょう。
・open関数で取得したファイルは、()関数で閉じる必要がある。
・with~as構文を使うことで処理中に()が発生しても必ず最後にファイルを閉じることができる。
・open関数の引数のうち、modeのデフォルト値は()である。
・open関数の引数であるfileでは、開くファイルの()を指定する。

答えはこちらの記事の最後に!
【Python連載】テキストファイルから行を抽出する


前回の確認問題の回答例

前回の記事はこちら→【Python連載】テキストファイルを読み込む

前回はこんな問題でした。

以下の選択肢から、正しいものを選んでください。
1.open関数の引数には、ファイル名を指定する。
2.open関数で開いたファイルは、ファイルオブジェクトとして扱われる。
3.readメソッドは、開いたファイルの1行目を読み取るメソッドである。
4.readlinesメソッドで返る値はリストである。

選択肢を確認してみましょう。
1番、open関数の引数にはファイル名ではなく、ファイルの絶対パスもしくは相対パスを指定する必要があるため不正解です。
2番は正解です。
3番、readメソッドはファイルオブジェクトの内容をすべて読み込んで、1つの文字列として返すメソッドですのでこちらは不正解です。
4番は正解です。

連載目次

独学で学ぶ Pythonプログラミング 連載目次