with構文を使ったファイル操作

9.2 with構文を使ったファイル操作

ファイル操作はwith構文と併用するのが一般的です。with構文を使うことで記述ミスをなくしたり、ソースコードが簡潔になりプログラムがわかりやすくなります。 ではwith構文とはどういったものなのでしょうか?

9.2.1 with構文とは

with構文は、通信処理やファイル処理など、開始と終了の処理が必要な一連の操作において、有効な構文です。
通常、これらの処理を行うためには、開始や、closeメソッドのような終了の処理を行わなければなりませんが、with構文を利用すると、記述なしで絶対に実行してくれます。
また、組み込み関数open()のように、開始時の処理のためのメソッド「__enter__メソッド」と、終了時の処理のためのメソッド「__exit__メソッド」を含むクラスに対して、with構文は有効です。
主にはファイル操作で使用されることが多く、それ以外だと通信処理、データベース処理で使えるので、これらの操作で使用すると認識していただいて問題ないでしょう。

書式:with構文

    with クラス名()  as 変数名:
        変数名.メソッド()
        …
	

9.2.2 ファイル操作への応用

続いてファイル操作にwith構文を応用させる方法について確認していきましょう。

書式

    with open(‘ファイル名.拡張子名’,'モードの内容', encoding='エンコード’) as 仮変数名
        仮変数名.メソッド名()
        …
	

asの後に指定した仮変数に、open関数の内容が格納され、with構文内では、仮変数名.メソッド名()でメソッドを取得することができます。

凡例

実行結果

	Python
	Java
	SQL
	

with構文は、通信処理やファイル処理など、開始と終了の処理が必要な一連の操作において、有効な構文です。
通常、これらの処理を行うためには、開始や、closeメソッドのような終了の処理を行わなければなりませんが、with構文を利用すると、記述なしで絶対に実行してくれます。

9.2.3 with構文を使ってCSVファイルの読み込むプログラム

with構文、open関数を使ったCSVファイルを読み込んだプログラムを確認していきましょう。

ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第9章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第9章.ipynb

    #with構文開始、sample.csvの読み込み
    with open('sample.csv','r',encoding='utf-8') as r:
        #sample.csvの各行のデータを読み込み
        for coms in r.readlines():
            coms = coms.split(',')
            #sample.csvの各行の各値を出力
            print(coms[0],'さんのPCのOS:',coms[1],'、メモリ:',coms[2])
	

実行結果

	田中 さんのPCのOS: windows 、メモリ: 70

	佐藤 さんのPCのOS: mac 、メモリ: 54
	

解説

まずこのCSVファイルでは以下のような構成で作成されております。

A列に氏名、B列にOS名、C列にメモリー容量といった内容です。
当プログラムのソースコードでは2~7行目でwith構文が記載されております。

    with open('sample.csv','r',encoding='utf-8') as r:
        #sample.csvの各行のデータを読み込み
        for coms in r.readlines():
            coms = coms.split(',')
            #sample.csvの各行の各値を出力
            print(coms[0],'さんのPCのOS:',coms[1],'、メモリ:',coms[2])
	

2行目がwith構文の開始行となっており、以下の内容を満たすopen関数を指定しており、構文内ではこちらのopen関数が仮変数rに格納されております。

【open関数の仕様】

  • 対象のファイル:「sample.csv」
  • モード:「読み込みモード r」
  • エンコーディング:「utf-8」
    with open('sample.csv','r',encoding='utf-8') as r:
	

4~7行目で、以下の仕様を満たすfor文を行っております。

【for文の仕様】

  • イテラブルオブジェクト:r.readlines()※「sample.csv」の各行がリスト型で格納されています
  • 仮変数:coms
    for coms in r.readlines():
        coms = coms.split(',')
        #sample.csvの各行の各値を出力
        print(coms[0],'さんのPCのOS:',coms[1],'、メモリ:',coms[2])
	

各セルのデータを取り出す上で、「r.readlines」には各行のデータが「カンマ,」区切りでまとめて文字列として格納されております。

図 9.2 1: r.readlines()に格納されているデータ状況

各行のデータを分割するために、split関数を使用します。split関数は、カンマなどの区切り文字を引数に指定することで、文字列を分割し、リスト型のデータを返すことができる関数です。
また、このfor文におけるcomsは、r.readlines()の各要素が格納されております。

【comsの格納状況】

そのため5行目にて、split関数を介して文字列として格納されている各データの情報を、カンマ区切りで分割しリスト型変数として各セルのデータを、comsに格納し直します。

    coms = coms.split(',')
	

図 9.2 2:split関数を介してデータ分割

リスト型に分割されたので、7行目で、氏名を表すcoms[0]、OS名を示すcoms[1]、メモリーを示すcoms[2]をそれぞれ出力しております。

    print(coms[0],'さんのPCのOS:',coms[1],'、メモリ:',coms[2])
	

9.2.4 入れ子上のwith構文のプログラム

with構文はif文やfor文などと同様、入れ子(ネスト)にすることもできます。
書き込みと読み込みをするためには、書き込み用のファイルオブジェクトと読み込み用のファイルオブジェクトをそれぞれ宣言し、クローズしなければなりませんでしたが、with構文を入れ子にするとどうなるのでしょうか?

以下では入れ子上のwith構文を介して、書き込み、読み込みを行うプログラムを確認していきましょう。

ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第9章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第9章.ipynb

    names = ['佐藤\n','田中\n','鈴木\n','山田']

    with open('sample3.txt','a',encoding='utf-8') as a:

        for name in names:
            a.write(name)

        with open('sample3.txt','r',encoding='utf-8') as r:
            for i in r.readlines():
                print('名前:',i)
	

実行結果

	

解説

まず1行目で、4つの要素を含むリスト型変数namesを宣言しております。

    names = ['佐藤\n','田中\n','鈴木\n','山田']
	

続いて3~10行目で、with構文を記述しており、指定のopen関数を仮変数aに格納しております。

    with open('sample3.txt','a',encoding='utf-8') as a:

        for name in names:
            a.write(name)

        with open('sample3.txt','r',encoding='utf-8') as r:
            for i in r.readlines():
                print('名前:',i)
	

こちらのwith構文で宣言したopen関数の仕様をまとめると以下の通りです。

【open関数の仕様】

  • 対象のファイル:「sample3.txt」
  • モード:「追記モード a」
  • エンコーディング:「utf-8」

with構文内では5、6行目でfor文を介してnamesから1つずつ要素を取り出し、write()メソッドで「sample3.txt」に値を書き込みます。

    for name in names:
        a.write(name)
	

さらにwith構文内で、入れ子上にwith構文内を記述しており、こちらのwith構文内で指定したopen関数を仮変数rに格納しております。

    with open('sample3.txt','r',encoding='utf-8') as r:
        for i in r.readlines():
            print('名前:',i)
	

新しく記述したwith構文の仕様をまとめると以下の通りです。

【open関数の仕様】

  • 対象のファイル:「sample3.txt」
  • モード:「読み込みモード r」
  • エンコーディング:「utf-8」

こちらのwith構文内では、9、10行目で以下の仕様のfor文が実行されており、「sample3.txt」の各行の情報が仮変数iに格納され出力されてます。

【for文の仕様】

  • イテラブルオブジェクト:r.readlines()※「sample3.txt」の各行がリスト型で格納されています
  • 仮変数:i

実行結果には何も表示されておりませんが、sample3.txtを確認すると「佐藤、田中、鈴木、山田」のデータが各行に格納されております。
これはwith構文を入れ子にした場合、親のwith構文(書き込み用)がcloseするタイミングが、子のwith構文(読み込み用)が完了した後になるからです。
書き込み用の処理がクローズした後に、読み込み用の処理を実行しないと書き込んだ内容が反映されないので注意しましょう。

ファイルパスの指定方法

本章で扱うファイルはプロジェクト直下で扱えるファイル(相対パスで指定できるファイル)のみで扱ってきましたが、フォルダや階層が異なるファイルを指定する際には、対象のフォルダを指定する必要があります。
以下では絶対パスでファイルを指定する方法(フォルダ名を全て記載する方法)、プロジェクト直下の相対パスでファイルを指定する方法をまとめてみました。

【絶対パスの場合】

  • C:\\フォルダ名\\フォルダ名…\\ファイル名.拡張子
  • C:/フォルダ名/フォルダ名…/ファイル名.拡張子

【プロジェクト直下の相対パスの場合】

  • ファイル名.拡張子
  • フォルダを指定する場合:フォルダ名\\ファイル名.拡張子 または フォルダ名/ファイル名.拡張子

NEXT>> 9.3 本章のまとめ