前回の投稿「Python3 超入門(4):条件分岐(if文),標準入力」の最後に次のようなことを書きました.
さて,私はといいますと,今後は「超入門」ではなく「入門」というシリーズ(?)で,pythonの基本的の使い方のメモを書いていきたいと思います.内容は言語処理100本ノック 2015の2章からの内容をやろうかなと思っています.
ということで,言語処理100本ノック 2015の2章を空き時間でぼちぼち進めてたのですが,前回までの投稿ではまだ基礎的な内容を伝えきれていないと考えたので,もう少しだけ「超入門シリーズ」を続けさせていただきます.
言語処理100本ノック 2015の2章は「UNIXコマンドの基礎」となっていますが,内容はpythonを使うにあたって出来ておくべき操作ばかりです.必要な知識をどんどん抜き出していこうと思います.今回の投稿では主にファイル操作を説明します.
PATH(パス)について
ファイル操作をするということは,作成するpythonファイル以外に,何か読み込んだりするファイル,あるいは何か書き込んだりするファイルがあるはずです.Pythonのルールとして「特に指定されていない場合は,pythonのプログラムでファイルを読むこむような指示があった場合はその実行しているpythonプログラムと同じフォルダの中から探す」というのがあります.この「pythonのプログラムが探せる場所」のことを「パス(Path, 道)」といいます.
正確に説明すると,「同じフォルダの中」はパスの一部です.試しに次のようなプログラムをファイルに書いて実行してみましょう.もしくはコマンドプロンプトを起動して入力するだけでも構いません.
import sys print(sys.path)
これを実行すると,様々なフォルダの位置が表示されるかと思います(このように表したフォルダの位置を「絶対パス」とも言います).これらのフォルダの一覧が,Pythonのプログラムの中で指示したファイルやプログラム(クラス)を探してくる場所,つまりpythonのパスになります.
pythonで外部ファイルを読み込む
では早速,実際どのようにしてpythonのプログラムにファイルを読み込ませるのか見てみましょう.まず,新しくフォルダを作成し,そのフォルダの中に「file.py」という空のpythonファイルとhightemp.txtというテキストファイルを保存しましょう.こちらのテキストファイルは言語処理100本ノック 2015で用いているものになります.そして「file.py」の中身を次のように作成して実行してみましょう.
with open ('hightemp.txt', 'r', encoding='utf8') as input: print(input.read())
これを実行すると,先ほどの「hightemp.txt」というテキストファイルの中身がそのまま出力されたかと思います.
ファイルの読み込みができるように開く(扱えるようにする)
with open ('filename', 'r', encoding='utf8') as input:
と書くことで,「filename というファイル名のファイルを,読み込み(read)専用で開きます.ちなみに,文字コードは UTF-8 ね.あと面倒だから,今後このファイルのことはinputっていう名前で扱います」という指示になっています.「開きます」とはいっても実際にウィンドウで表示するのではなく,pythonが扱えるようにするという意味です.文字コードについては初めのうちはおまじないのように考えていただいてもよいですが,書いておかないとエラーを出される場合があるので注意しましょう.読み込んでいるファイルの文字コードに合わせて変更する部分になります.先ほどの実行例では,ファイル名は「hightemp.txt」でしたので,同じフォルダ内にある「hightemp.txt」というファイルを読み込んできてくれました.行末にある「as input」は「今後このファイルのことはoutputっていう名前で扱います」という意味です.”input”の部分は各自好きな名前に変えていただいて問題ありません.これ以降,ファイル”hightemp.txt”に関する操作をする際には「input.(操作の指示)」のような形をとります.
Python の自動メモリ解放
Pythonで外部ファイルを扱い際に with open を使う特徴として「一度ファイルを開いてしまえば,インデントがなくなるまではファイルは開きっぱなしで,インデントがなくなると自動的にファイルを閉じてくる」というものがあります.先ほどから使っている「ファイルを開く」ということは,実際にウィンドウで開くわけでなく,「データが保存されているハードウェアから,コンピューターのメモリにデータをコピーして,いろいろ扱えるようにする」ということをしています.保存されている場所で直接作業しない理由は,メモリではデータの読み書きが早くできるからです.
大きなファイルを読み込むともちろんメモリを占める大きさも大きくなるので,もう作業が終わって使わなくなった部分についてはもうメモリを占めている必要はありません.「もうメモリ使う用事は終わったから片付けます」とういことを「メモリを解放する」といいます.このメモリを解放する作業をしないと,有限なメモリの領域を使わないデータがたまっていって使えなくなってしまいます.机に書類がたまりすぎて,作業スペースが減っていくイメージです.なのでメモリ解放は非常に大事な作業なのですが,プログラム言語の特徴として「特に言われなければやらない」というのがあるので,「メモリを解放しろ」という指示がないとやってくれません.しかしpythonの with open を使ってファイルを開くと,インデントがなくなると自動的にメモリを解放してくれます.
ファイルから,文字列を読み込む
ファイル操作の例として,今回は「read」を例に出しました.「input.read()」とすることで「inputというファイルの中身を文字列として読み込め」という指示になります.今回はprint分の中にこの指示が入っているので,ファイルの中身が出力されたわけですね.
読み込めるようにしたファイルの操作
ここからはpythonにいろいろ変更を加えて,どのようなファイル操作があるのか見ていきたいと思います.
一行ずつ文字列として読み込む
次のようにpythonファイルを変更します.
with open ('hightemp.txt', 'r', encoding='utf8') as input: print(input.readline())
変更後に実行すると「高知県 江川崎 41 2013-08-12」と表示されるでしょう.これは”hightemp.txt”の一行目ですね.
お察しの通り「input.readline()」とすることで「inputというファイルを一行読むという」指示になります.この指示ですが少し注意がいります.試しに次のプログラムを実行してみましょう.
with open ('hightemp.txt', 'r', encoding='utf8') as input: print(input.readline()) print(input.readline())
すると今度は「高知県 江川崎 41 2013-08-12(改行)埼玉県 熊谷 40.9 2007-08-16」のように表示されます.これを見ていただくと「readline()は実行されるたびにファイルの前から順番に1行ずつ読み取る機能」であることがわかります.pythonファイルの2行目のinput.readline()が実行されることで”hightemp.txt”の1行目が出力され,pythonファイルの3行目のinput.readline()が実行されることで”hightemp.txt”の2行目が出力されています.
行頭に戻る:seek(0)
readline()を使うことでファイルの行を順に読み取ることができましたが,よく考えるとこれでは「前の行に戻ってもう一度読み取る」ということができません.実践問題として,ファイルを一度読み込んだとしても,同じ個所をもう一度読み込みたい場合は十分考えられます.そのようなことをしたい際にはseekという機能を使います.先ほどのコードに次のような行を追加してみましょう.
with open ('hightemp.txt', 'r', encoding='utf8') as input: print(input.readline()) input.seek(0) print(input.readline())
これを実行すると「高知県 江川崎 41 2013-08-12(改行)高知県 江川崎 41 2013-08-12」と出力され,”hightemp.txt”の一行目が二回読み込まれていることがわかります.
シーク(seek)というのは,カーソル(コンピューターで文章を作成する際に入力している部分に現れる,チカチカする縦棒)をイメージしていただければよいでしょう.カーソルが表しているのは「文章中で今自分が入力しようとしている位置」であるのに対して,シークが表しているのは「コンピューターのメモリの中で,今自分が読み取っている位置」です.これを念頭に先ほどの「input.seek(0)」というのを考えると,これは「inputという名前になっているファイルの0バイト目,つまり行頭」という意味です.
ここでseekの中の数を0からほかのに変えて実行してみましょう.例えば3や6を入れて実行すると「高知県」の文字の一部か切り取られて表示されるかと思いますが,それ以外の数を入れてみるとエラーが出てしまいます.その理由について考えることはいい練習なので理由は書かないでおきます.ヒントとして「UTF-8 の日本語文字は何バイトか」ということだけ書いておきます.
新たにファイルを作成して書き込む
ファイルの書き込みができるように開く(扱えるようにする)
ファイルの読み込みの際には,そのファイルが同じフォルダ内にあることが前提でした(正確には,読み込みファイルがパスに含まれていることでしたね).今度はpythonでファイルを新しく作ることを学びますが,この際も特に指定がなければpythonファイルがあるフォルダに出力されます.file.pyファイルを次のように編集してみましょう.
with open ('shuturyoku.txt', 'w', encoding='utf8') as output: output.write('1gyoume' + '\n') output.write('2gyoume' + '\n')
これを実行すると次のようなファイルがfile.pyと同じフォルダに作成されているかと思います.
1gyoume 2gyoume
まずpythonファイルの方ですが,こちらは特に先ほどと大きな違いはありません.一つ決定的な違いは with open のオプションで,先ほどは’r’として読み込み専用としたところを,今度は‘w’と書くことで書き込み(write)専用となっています.このように書くことで”shuturyoku.txt”というファイルが書き込み専用として新しく作成されます.
書き込みファイルへの書き込み
書き込み可能なファイルを開いたら,次はそのファイルに文字を書きましょう.上のコードから予想がつくかと思いますが,「output.write(‘hogehoge’)」と書くことで「outputと名前を付けた書き込み用のファイルに,hogehoge という文字を出力しなさい」という指示になります.注意点は,writeのかっこの中は必ず文字列(str型)でなければならないということです.print文の場合はかっこの中にint型の整数や,float型の浮動小数を入れてもその値を出力してくていました.しかし,ファイルにwriteで書き込む際には必ずstr型の文字列でなければいけません.str型への変換についてはこちらの投稿でformatの使い方が書いてありますので,そちらを参考にしていただければと思います.
Python3 超入門(1):文字の扱い方の超基礎で扱った通り,「\n」は改行を表しています.
こちらもwith openの方法を使っているため,インデントがなくなると自動的にメモリが解放されます.