Pythonでテキストファイルに書き込み
今日は、Pythonを書く人なら誰でも知っていると思われる、テキストファイルの書き込みについての小ネタ。
なぜか、「python、ファイル、書き込み」とかでググると、以下のような感じの説明をしてるウェブサイトばかりが出てくる。
-
open
関数で書き込みモード("w")のファイルオブジェクト(_io.TextIOWrapper
)を作成して、 -
write
かwritelines
で書き込む!!!!!!!!!
確かに、これが最も基本的な書き方であることは間違いないが、正直なところwrite
関数での書き込みは面倒くさいし意外と難しい。なんと言っても、書き込み内容を文字列(str
)型に整形する必要がある。テーブル形式で書き出したいときなんて、区切り文字までつけないとならないし発狂ものである。(標準のcsvモジュールとかpandasとかnumpyのcsv出力の機能を使えばいいという指摘は最もである。しかし、ダメだとは分かっていても、ヘッドにコメントを付けたいみたいなときもあるわけで、標準のwrite関数を使わざる得ない時もあるわけである。)
実は、そんなときはwrite
ではなくてprint
を利用すると、誰でも簡単にテキストファイルに書き込みができるようになる。
printを用いたテキストファイルへの書き込み
例えば、以下のような2次元リストをテキストファイルにcsv形式で書き込むこと考えてみよう。
sample_data = [["Name", "Sex", "Age", "Weight", "Height"],
["Hoge", "M", 41, 74, 170],
["Fuga", "M", 42, 68, 166],
["Piyo", "M", 32, 70, 155],
["Hogera", "M", 39, 72, 167]]
これを、write関数で書き出そうとすると、以下のような感じになる。
with open("sample.csv","w") as o:
for row in sample_data:
o.write(",".join(map(str, row)) + "\n")
まぁ、分かる。何やってるか分かるけど、正直、書きにくいし読みにくい。念の為write
のところのコードを解説すると、
-
row
の各要素が数値であることもあるため、map
関数でrowの中身を全て文字列に変換。 -
map
関数の返り値をjoinに渡すことで、","を区切り文字にして、各要素が連結された文字列を生成。
ということをやっている。しかし、map
とかjoin
とか正直、初心者には難易度が高めであんまり使い勝手が良くない。
しかし、print
を使えば以下のように直感的なコードで書き込むことが可能だ。
with open("sample.csv","w") as o:
for row in sample_data:
print(*row, sep=",", file=o)
お分かり頂けただろうか。map
とかjoin
とか、そしてwrite
すら使う必要はないのである。print
だけで全てが完結する。なにより、数値を文字列に変換する必要がない!。素晴らしい。
以下解説
まず、最も重要なことはprint
にはfile
という引数が用意されていて、これに.write
をもつファイルオブジェクトを指定してあげれば、デフォルトだと標準出力に出力される内容をファイルに書き込むことができる。つまり、
with open("hoge.txt", "w") as o:
print("Hello world!", file=o)
という使い方ができるわけである。ただ、まぁこれだけならwrite
と差はない。しかし、以下のような場合ならどうだろうか。
a = 123
with open("hoge.txt", "w") as o:
print(a, file=o)
そう、数値だって文字列に変換することなく書き込むことができるのである。もう、これだけでprint
の方が使いやすい。
また、print
にはsep
という区切り文字を指定するための引数まで用意されている。例えば、
>>> print( 1, 2, 3, sep="hogehoge")
1hogehoge2hogehoge3
といったことができる。ただ、単にこの方法でlistの中身を書き出そうとすると、以下のようにlist
の要素を一つずつ指定する必要があって、あまり実用的ではない。
>>> values = [1,2,3]
>>> print(values[0], values[1], values[2], sep="hogehoge")
1hogehoge2hogehoge3
そんなとき活躍するのがアスタリスク、*
を用いることでlist
の中身を展開することができる。これを使うと以下の例のように、list
の中身を一度にprint
に渡すことができる。
>>> values = [1,2,3]
>>> print(*values, sep="hogehoge") #print(values[0], values[1], values[2], sep="hogehoge")と同じ意味
1hogehoge2hogehoge3
つまり、最初のcsvの出力の例では、print(*row, sep=",", file=o)
でrow
の各要素を","区切りでファイルに書き出すということをやっていたのである。rowの中身は文字列と数値が混ざっていることもあるわけだが、printで書き出す場合には何も気にする必要はない。そのまま、期待通りの結果が出力される。
また、file
をfile=None
として指定すれば、標準出力に出力されるので書き出しの結果を一度確かめたいみたいなことも手軽に行うことができる。
ほぼ同じ記事が既ににありました、ごめんなさい
多くのテキストやwebの説明だとwrite
による書き込みばかり紹介されていて、意外とprint
の便利さが知られてないんだよなぁと思って記事を書いてみたけど、調べてみたら同じような記事が過去にありました。ほとんど重複記事になってしまった。すいません。
https://qiita.com/pytry3g/items/aa38d8c2acf59b90aaac