40
30

More than 1 year has passed since last update.

pythonでテキストファイルに書き込みするならwrite使うよりprint使う方が簡単だよ。

Last updated at Posted at 2022-03-13

Pythonでテキストファイルに書き込み

今日は、Pythonを書く人なら誰でも知っていると思われる、テキストファイルの書き込みについての小ネタ。
なぜか、「python、ファイル、書き込み」とかでググると、以下のような感じの説明をしてるウェブサイトばかりが出てくる。

  1. open関数で書き込みモード("w")のファイルオブジェクト(_io.TextIOWrapper)を作成して、
  2. writewritelinesで書き込む!!!!!!!!!

確かに、これが最も基本的な書き方であることは間違いないが、正直なところ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のところのコードを解説すると、

  1. rowの各要素が数値であることもあるため、map関数でrowの中身を全て文字列に変換。
  2. 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で書き出す場合には何も気にする必要はない。そのまま、期待通りの結果が出力される。
また、filefile=Noneとして指定すれば、標準出力に出力されるので書き出しの結果を一度確かめたいみたいなことも手軽に行うことができる。


ほぼ同じ記事が既ににありました、ごめんなさい

多くのテキストやwebの説明だとwriteによる書き込みばかり紹介されていて、意外とprintの便利さが知られてないんだよなぁと思って記事を書いてみたけど、調べてみたら同じような記事が過去にありました。ほとんど重複記事になってしまった。すいません。
https://qiita.com/pytry3g/items/aa38d8c2acf59b90aaac

40
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
30