このページの本文へ

遠藤諭のプログラミング+日記 第11回

人生のたいていのことはPythonでできる?

2016年12月09日 09時00分更新

文● 遠藤諭(角川アスキー総合研究所)

  • この記事をはてなブックマークに追加
  • 本文印刷

10分後にあなたはPythonのコードを書いている

 「女人は我々男子には正に人生そのものである。即ち諸悪の根源である」と芥川龍之介が書いているそうだ。読書感想文でお世話になった『羅生門』とか、『河童』とか、もっと深刻なテーマが専門にみえる芥川龍之介がそんなこと言うとは驚きである。これに倣っていうなら、コンピューターとは人生そのものだと言ってよいと思う。「コンピューター」は、「運用」(面倒を見ること)を必要とするが、そのぶんできることはずっと広がるし、人をクリエイティブ(生産的)にするからだ。

 ということで、やっぱりコンピューターのほうがスマートフォンよりも楽しい。「スマートフォン」は、生活の手間をはぶくリモコン程度の存在に過ぎず、深いことができないから、人を、ザッピング的に、キュレーション的に、BOT的にする。国立社会保障・人口問題研究所によると、いまの若い人たちは異性の交際相手を希望しない割合が年々増加しているそうだが、それは世の中がスマートフォン的になり過ぎたからではないかとも思える。

 さて、なんの話かというとひさしぶりにプログラミング言語を覚えようとしている。具体的には「Python」(パイソン)をいじりはじめている。どうも、こいつが我々とコンピューターとの関係を、より親密に、深いものにしてくれそうだと思ったからだ。

 『確かな力が身につくPython「超」入門』(鎌田正浩著、SBクリエイティブ)という本によると、「アメリカの情報工学のコースを持つ上位校を調査したところ、Pythonを最初に教える学校は7割にものぼります」とある。これは、本を買わせるための売り文句の雰囲気もなきにしもあらずだが、いまをときめく電子工作のマイコンボード「Raspberry Pi」も、開発言語としてPythonを推奨しているそうだ。入門に向くばかりではない。米リクルーティングサイトのCODEEvalによると、5年連続でPythonが最も人気のある言語だとある。これは、そのまま言語の人気というよりも利用が増えているのに対して使える人が不足しているという意味なのだと思うが。

 ところで、この「Python」(パイソン)という名前、70年代英国のコメディ番組『空飛ぶモンティ・パイソン』(Monty Python's Flying Circus)に由来する。私と同世代の人間なら、同番組の「恐るべき殺人ウサギ」、「バナナを持った強盗から身を守る方法」、「シリーウォーク」、「自転車修理マン」などのナンセンス一筋なエピソードが心地よく頭に浮かんでくる人が少なくないはずである。調べてみると、作者であるオランダ人のグイド・ヴァン・ロッサム(Guido van Rossum)という人物は、やっぱり、私と同時代の人間だそうだ(少し下だけど)。

 彼は、このネーミングについて、「PascalやAdaやEiffelなど、プログラミング言語に有名な人物の名前が付くという伝統にも合致していますよね」などとブログで書いていたりする(モンティ・パイソンはグループ名でもある)。テレビ番組の名前が使われるのだとしたら、日本だったら「ゲバゲバ90分!」なんて名前になっていたかもしれない。ちなみに、Pythonには、“2”と“3”の2つのバージョンの流れがあるが、私が勉強中のPython3は、“西暦3000年”(!)に公開予定の理想のPythonとして開発されていたものらしい(このバカバカしいスケール感! モンティ・パイソンのトレードマークである“足”を載せておかないわけにはいきません)。

Bronzino [Public domain], via Wikimedia Commons

 さて、「人生のたいていのことはPythonで出来る?」というのはあながち冗談でもないつもりだ。そんな偉そうなことをいう立場にはないのだが(かじったばかりなので)、Pythonのために、世の中の神羅万象とも思えるライブラリが用意されているように見える。Pythonといえば、Google App Engineで使えるというので注目した人もいるかもしれない。とにかく、関数さえ呼び出せば実にさまざまなことができてしまいそうに感じてしまう。

 などというと、「自分でプログラムを書かなくても、世の中には、便利なソフトウェアやサービスがたくさんあるでしょ」と言われそうである。しかし、私としては、これはどちらかというと「生き方」に類する問題なのだ。山に登ったり、料理を楽しむ人たちのことを考えてほしい。エドモンド・ヒラリー(エベレスト登頂)や、北大路魯山人とはほど遠くても、自分なりに体と脳ミソを動かしてなにかやってみるのはどうだろう。

 とはいっても、私の場合は、これを仕事にしてアプリを作って売りだそうとか考えているわけではない。そうしたことのためには、きちんとしたPythonの入門をすべきである。本格的な登山には、ちゃんとした知識と装備が必要なのと同じだ。そうした場合のための情報もさまざまな形で提供されいる。ありがたいことに、Pythonソフトウェア財団(Python Software Foundation)のマニュアルを、Pythonドキュメント翻訳プロジェクトが日本語化してくれている。

 それに対して、私がやろうとしていて、ここで伝えたいと思っているのは、いわば「汎用パソコン自動化スクリプト言語」としてのPythonである。ふだんパソコンを使っていて、同じことの繰り返しだったり、目をこらして頑張らないとできない面倒なことがたくさある(少なくとも私には)。そんな、いままで自分で手でいちいちやっていたことや、手がつけられなかったような作業を、Pythonで、ラクにできたりするんではないかという気配なのだ。

 実は、そうしたネタも一般的な開発情報のほかにあるだが(本サイトでRubyやGoを編集してくれている鹿野桂一郎さんに『Automate the Boring Stuff with Python』という本を教えてもらった。私のほうが手元のチマいことのをやろうとしているが「ラク」しようという発想は同じか?)、ここであえて次のようなことを言いたいと思っている。

道具としてのPython

語り合える相手としてのPython

考えさせてくれるPython

 それは、“知的ペット”、あるいは、“電子的子分”というのがいちばん近いのかもしれない。便利ということもさることながら、冒頭で書いたようにスマホですっかり鈍ってしまった、我々の身体と脳ミソの感覚をピキピキと再生させてくれる。このあたりの感覚は、Rubyなどスクリプト言語なら同じだよとも言われそうではあるのだが、とにかく、Pythonをはじめてみたというわけだ。

これはきちんとした“Python入門”ではなてく、“電子的子分”がほしいという話だ

Pythonソフトウェア財団のトップ画面。

 自分のコンピューターにPythonをインストールする方法については後で触れるつもりだが、Pythonの体験だけなら、Pythonソフトウェア財団のトップ画面から試すことができる。コードの表示されている黒い部分の中にあるオレンジ色の四角い部分(写真では赤い矢印で示してある)にマウスをあてると「Lounch Interactive Shell」とポップアップして、クリックするとWebでPythonの体験ができる。


print('Hello, World!')

 これで、もう「あなたはPythonプログラマーだ!」などとはいえないが、ちょっとうれしいでしょう。さすがに、これだけではつまらないので次のようにも打ってみよう。


import os
os.listdir()

とりあえずお決まりの“Hello, Wolrd”と“ディレクトリ内のファイル表示”をさせたところ。

 これは、WindowsやMacOSでいえば、ただのファイル一覧が表示されている状態だ。「これで何がうれしいの?」と言われそうだが、この画面で、あなたはすでに自分のコンピューターにPythonをインストールしたのと同じようにPythonを使っている!

 ついでながら、ディレクトリの移動、ディレクトリを作る、名前の変更などは次のように行う。


os.mkdir('room1')
os.chdir('room1')
os.chdir('..')
os.rename('room1', 'test-room1')

 Pythonでは「import」と書くことで、さまざまな便利な機能を随時追加できる(別途インストールが必要なこともあるがそれもシンプルで分かりやすい)。すでに、OSの機能を使うのに「import os」とやったが、これがありがたいのは、WindowsだろがMacOS Xだろうが、同じOSであるかのような気分で(?)ファイル操作ができる。それで、定番なのが、globというモジュールだ。下のように実行してみよう。


import glob
files = glob.glob('*.txt')

 これで、ファイルの一覧がデータの形で手に入る。先ほどの「os.listdir()」との違いは、"*.txt"というパターンに合致したものだけを持ってくる(いまの場合は"README.TXT")。「持ってくる」と書いたが、より具体的にはPythonの“リスト形式”と呼ばれるデータとして持ってくる。Pythonは、プログラミング言語なので、こうしてリスト(データ)になったら自由自在なんでもできる。これを1つずつ取り出して名前を変更するには、次のように続けて書いてみよう。


for  name in files:
  new_name = name.replace('READ', 'YONDE')
  os.rename(name, new_namae)

 いきなり複雑になったように見えるが、要するにファイル名の中の文字列"READ"を"YONDE"に変更したわけだ。"for name in files"というのは、さっきのファイル名一覧を入れたリストから1つずつ取り出して処理を行うことを意味している。"README.TXT"が"YONDEME.TXT"に名前変更されたはずだ(これは戻しておいたほうがよさそうだが)。ここで重要なのは2行目、3行目が、2文字ほど字下げ(インデント)してあることだ。Pythonでは、字下げが文法そのものになっている(そのかわりfor文の終わりにわざわざ閉じ括弧などを書かなくていい)。

 さて、こうなると1つのフォルダの中だけではなく、自分のハードディスクの中のあるフォルダから先のすべてのサブフォルダの中まで、同じようにやってみたいという気分になる。実は、そんな人のために、Pythonには、「os.walk」というものが用意されている。これは、文字どおりディレクトリのツリーの中を歩くように巡ってくれるというものだ。


import os
for root, dirs, files in os.walk('.'):
  for file in files:
    full_path = os.path.join(root, file)
    print(full_path)

ハードディスクの中をぐるぐる走り回って同じ処理をさせたりするための基本スクリプトです。ちなみにシェル上では上矢印で過去の入力を呼び出して編集し直して再実行できます。赤矢印についてはこのあと述べます。

 さて、このくらいになってくると、いくらなんでもキーボードでその都度入力しているのはタルくなってくると思う。そこで、Pythonソフトウェア財団のこのシェルの本来のサービスである「PythonAnywhere」のお世話になってみることにしよう。シェル画面の右下にある「Online console from PythonAnywhere」の部分(赤い矢印で示してある)をクリックすればよい。

 これがいいのは、Pythonの3.5、3.4、3.3、2.7のほかに、より使いやすくしたIPython、シェルのBashなども使えることだ。アカウントを作ったら、「Console」タブから環境を選び、「Files」タブから手元で作ったスクリプトをアップロードして使えばよい。私の場合は、パソコンのコマンドラインの感覚で使えるBashを使っている。"python"では2.7が起動してしまうので、"Python3"と叩いて使うようにする。

PythonAnywhereのアカウントを作ろう。

まずは無料のビギナーアカウントから。

メニューの「Dashborad」から「Console」のシェルを選ぶ。

「Files」からファイルのアップロードを行う。

 PythonAnywhereは、Pythonを学んで実際にウェブアプリを作って公開できるサービスで、ビギナーより先は有料プランが用意されている(IPythonも有料プランのみで利用可能)。なので、そちらに突き進むのもありだが、自分のマシンにインストールして使うことももちろんできる。私の場合は、Pythonソフトウェア財団のページから「Windows x86-64 executable installer」をダウンロードして実行した(1点、インストーラーの最初の画面で"Add Python to PATH"はチェックしておくとよさそうだ)。なんなくできてしまうので、可能ならこちらも積極的にやってみることをお勧めする(Pythonソフトウェア財団は寄付も募っている)。

Pythonソフトウェア財団
https://www.python.org/
Python3.5.1のダウンロードページ
https://www.python.org/downloads/release/python-351/
日本語マニュアル
http://docs.python.jp/3.5/
PythonAnywhere公式サイト
https://www.pythonanywhere.com/

 さて、このコラムはPythonをきちんと学ぶためのものではないと書いたが、そういう人でも、Pythonの入門を、たとえば、本で1、2冊、ザッと読んでみることをおすすめする。最初にまとまった知識を頭に入れておくと、あとで検索しながらやるのでも効率的だからだ。私が、最初に読んだのは『言語研究のためのプログラミング入門/Pythonを活用したテキスト処理』(淺尾仁彦・李在鎬著、開拓社)という本だった。漢字コードも扱いたいと思っていたので目的に合致していたのと、Pythonの文法については必要最低限のことが“手早く”まとめてあって速習向きだと思ったからだ。

お悩み自分で解決っていい。私がやりたかたったのはコレだった!

 さて、Pythonで何をやりたいと思ったのか? 最初にやってみたのは、「テキスト処理」だ。そして、もう1つはハードディスクにたまった大量の「デジカメ画像の整理」である。今回は、前者について実際にどんなことをやったかを紹介することにする。

 たぶんこれを読んでいる人の中にも、「たくさんの文字列置換をやる場合にどうするか?」という課題に直面したことのある人は多いと思う。同じような置換を大量にやるのは、とても退屈で時間のかかる作業だし、間違いも発生しやすい。そこで、Pythonだと、次のようにしてテキストファイル内の文字列置換ができそうだ。


import os, sys, re
filename = sys.argv[1]
gfile = open(filename, 'r')
for line in gfile:
  line = line.rstrip()
  line = re.sub(r'Monday', '月曜日', line)
  line = re.sub(r'Tuesday', '火曜日', line)
  line = re.sub(r'Wednesday', '水曜日', line)
  line = re.sub(r'Thursday', '木曜日', line)
  line = re.sub(r'Friday', '金曜日', line)
  line = re.sub(r'Saturday', '土曜日', line)
  line = re.sub(r'Sunday', '日曜日', line)
  print(line)

 このスクリプトを、たとえば「yobi.py」という名前で保存。一方、中身の文字列を置換したいファイルを「1.txt」として、コマンドラインから「yobi.py 1.txt」などと実行する(環境によっては「python3 yobi.py 1.txt」)。実際に動かした結果は、次のようになる。

加工元のテキストを表示させたあと上記のPythonスクリプトを実行したところ。

 スクリプトを見ていただくと、「sys.argv[1]」となっているのは、スクリプトに渡された"パラメーター"を意味していて、いまの場合は"1.txt"という内容が入ってくる。ここから1行分ずつ処理していくのが、「for line in gfile:」以下の部分だ。「line.rstrip()」というのは、行末についてくる「改行コード」を取り去っている。

 ところで、コンピューターで日本語のテキスト処理をしたい場合、どうしても漢字コードという問題がある。実は、Windowsなり、Macなりの中でとじている分には、このままでよい。ただ、私の場合は、どうせならどのシステムでも動かしたいのと、日本語(シフトJIS)以外の文字もあつかいたいと思っている。そこで、スクリプトファイルも、データのファイルもすべて"UTF-8(BOM無し)"という文字コードで保存している。私と同じようにしたい場合、3行目は、「gfile = open(filename, 'r', encoding='utf-8')」とする必要がある(Windowsの「メモ帳」が、"UTF-8(BOM無し)"で保存できないので注意が必要)。

 ところで、「r'Monday'」のようにしている「r」の意味は、「正規表現」というものを意味している。実は、単純にMondayと指定するだけでなく、次のように指定することで置換対象に該当する文字列をより具体的に示すことができる。


r'^Monday'		#行頭のMondayが該当
r'\(Monday\)' #括弧内のMondayが該当
r'(Monday|Mon)' #MondyとMonが該当
r'T....?day' #“.”は任意の文字、“.?”は任意の文字アリ、またはナシ
r'[MTWFS][a-z]*day' #「MTWFS」のどれかで始まり「a~z」の文字が0個以上

 正規表現は、いまさらながら置換や検索ではバツグンに威力を発揮する。これを知らないで人生を生きるのとそうでないのとでは、まるで豊かさが違うと思うので、まだ使ったことのない人は、ふだん使っているエディタなどでぜひやってみるといい。Pythonの正規表現の詳細については、公式のドキュメントをご覧いただきたい。

 しかし、上記のコードでは肝心の置換する文字列を書く部分がいかにも面倒である。ということで、加工したいテキストの前半にそれを列記しておけばよいコードを書いてみた。


import os, sys, re
filename = sys.argv[1]
tikan_jisho = {}
data_f = 0
gfile = open(filename, 'r')
for line in gfile:
  line = line.rstrip()
  if re.search(r'^//', line):
    motos = re.sub(r'^//([^ \t]*)[ \t]*.*', r'\1', line)
    motos = re.sub(r'\$s', '([^;]*)', motos)
    seiseis = re.sub(r'^//[^ \t]*[ \t]*(.*)', r'\1', line)
    tikan_jisho[motos] = seiseis
  else:
    for i in tikan_jisho:
      line = re.sub(i, tikan_jisho[i] ,line)
    print(line)

 これじゃなにがなんだか分からないといわれそうだが、そこは書くほうはお気楽、読むほうは大変というプログラミングの世界。実際は、見た目ほど大変なことではない。次のような形式で置換文字列を読みこんで文字列置換をするためのコードだ。


 //Monday	月曜日
 //Tuesday 火曜日
 //Wednesday 水曜日
 //Thursday 木曜日
 //Friday 金曜日
 //Saturday 土曜日
 //Sunday 日曜日

 要するに、1桁目に「//」と書いたら、続けて「置換前文字列」、空白やタブをおいて「置換後文字列」を書いておく。置換前の「Monday」にあたる部分には、正規表現が書けるので「^Monday」とやれば、行頭の「Monday」だけ置換対象になる。

文字列を置換したい文章の前半に置換したい内容を書いておき、Pythonでスクリプトを実行すると複数項目の一括置換が行われる。

 このスクリプト、プログラミング言語ということで1カ所だけイタズラ(?)がしてある。たとえば、次のように置換文字列を与えておく。


 //{挨拶}$s	こんにちは、\1さん! お世話になります。
 //{予定確認}$s;$s それでは、\1、\2、よろしくお願いいたします。お会いできるのを楽しみにしています。
 //{住所}$s 住所は、東京都千代田区富士見1-8-19 \1
 //{逆順}$s;$s;$s \1 \2 \3 を逆に並べると \3 \2 \1

 これの本文に、次のように書いてみたらどうなるか?


 {挨拶}山田
 {予定確認}8日;5時半~6時
 {住所}だよ!
 {逆順}赤;白;青

 するとスクリプトは、次のようなテキストを生成する。


 こんにちは、山田さん! お世話になります。
 それでは、8日、5時半~6時、よろしくお願いいたします。お会いできるのを楽しみにしています。
 住所は、東京都千代田区富士見1-8-19 だよ!
 赤 白 青 を逆に並べると 青 白 赤

 要するに、ただの文字列置換のスクリプトのはずが、ちょっとしたマクロというかジェネレーター的なことができてしまう。「//」ではじまる置換前文字列の{}で囲んだ右に「$s」と書いてある部分に書いてある文字列を、置換後の文字列の\1、\2、\3、\4……に組み込んでいるのだ(スクリプト上では11行目のたった1行でやらかしている。プログラムの1行って怖い)。

 さて、これを使ってなにがやりたかったかというと、ほかでもないこの記事を掲載しているASCII.JPに記事をあげるときのタグ付け(HTMLを生成する前に独自のタグが用意されている)をラクにやりたかったからだ。こんな20行にも満たないコードでも、単純なタグ付けや写真データの対応などが、物凄くラクになる。もちろん、編集部も工夫しているらしいのだが、私の場合、どうも対話的にじゃなくてこんな感じでプリプロセッサでやるのが好みなのだ。実際に与えるのは、以下のような形式の置換情報だ。


 // ^{見出し}$s	<h2>\1</h2>
 // ^{写真}$s;$s <cj:inc template="46" title="" element_id="\1;;;" memo="\2;;;" alt=";;;" />
 // {リンク=$s;$s} <a href="\1">\2</a>
 // ^([^<].*) <p>\1</p>
 // kao.jpg 1260667
 // seihin.jpg 1260668
 // file1.jpg 1260669

 ごちゃごちゃと<>で括ってあるのが、まさ生成したいタグ。「kao.jpg」を「1260667」というのは、ファイル名で書いたものをCMSのファイル番号に置換する意味だ。たとえば、次のような原稿のテキストを与えるとする。


 {見出し}これは見出しです
 {写真}kao.jpg;これは顔写真のキャプションです
 これは本文のテキストです。

 実行結果として、次のようなテキストを得るというわけだ。


 <h2>これは見出しです</h2>
 <cj:inc template="46" title="" element_id="1260667;;;" memo="これは顔写真のキャプションです;;;" alt=";;;" />
 <p>これは本文のテキストです。</p>

 たいしたことではないように見えるのだが、ややこしい記号列に正しいファイル番号を書いていくのは、神経を使うというものだ。ちなみに、「kao.jpg」という文字列は、一度、{写真}の置換文字列の中に組み込まれ、次に「1260667」へと再度置換されている。2度の置換は、同じような名前のファイルがあるとトラブルのもとなので「 //@kao.jpg」として「{写真}@kao.jpg」のように呼び出す運用がよいかもしれない(スクリプトで解決できそうだが現状ここまで)。実際に仕事で使っているスクリプトは、エラーチェックをもう少しまじめにやったり、写真のファイル名と番号の対応をCMSの出力からワンタッチで取り込めるようになっている(社内ローカルな話で申し訳ない)。

 ところで、これは余談になるがこういうファイル名と画像IDの対応のようなことは、コンピューター以降のあしき傾向かもしれない。紙のレイアウト用紙と写真(ポジ)で編集していた時代には、「合番」(あいばん)が常識だった。レイアウト上の図版は、見開きや記事の中で、1から順番に出席番号のように数字がふられる。使う写真のほうもポジ袋にダーマト(本来は手術用だがツルツルの樹脂の袋にも文字が書ける色鉛筆のようなもの)で、やっぱり1から出席番号のように数字をふって文字どおり一元化していたのだ。

 人は、"対応表と首っ引き"でなんかいい仕事はできないというのが私の持論だ。合番が凄いのは、レイアウト上の位置とそこに配置されるべき写真が"対応"ではなく"同一化"することである。私が、『月刊アスキー』編集部に入ったとき「これぞプロの仕事!」と思ったのは、これだった。脳ミソを空にすることを心がけることが、結果的により上位の概念に専念できることになる。

 さて、なぜ突然Pythonのコードを書いていくネタをこのコラムで書いたのか? 「暇なの?」とか「なんでいまさらこんなタイプの記事?」とか言われそうだ。しかも、恥ずかしげもなくいかにもシロウトなコードになっている。たぶん、はるかにエレガントで"Pythonらしい"書き方ができるはずだ。というよりも、本文中のコードが間違っていて正しく動作しない可能性もある(突っ込まれそう)。それから、今回、Pythonでやっているけど、Rubyで同じことをやってみるのも楽しいと思う(1年半ほど前にRubyをすこしかじっていた。ケーキを3つに分ける問題の計算に使ったのだが、同じようにスクリプト言語として今回のようなテーマに向くわけなのだ)。

 しかし、こうして遊び感覚でプログラミングすることで、パソコンでやる仕事がラクになるなんて、「これはやらない手はないでしょう!」ということでこれを書いている。プログラミングの入門は、やって実際に意味があるテーマでやるのがいちばんなのだ。

 次回は、ハードディスクの中に大量にたまったデジカメ画像の整理の話を書くつもりだ。Pythonで、デジカメ画像のファイルに埋め込まれた「Exif」というカメラ名や撮影日付などいろんな情報が扱えるのだ。全国のデジカメ愛好家のみなさん、写真の中のふだん見えないデータに触れるなんて、それだけで、ワクワクしませんか?

遠藤諭(えんどうさとし)

元プログラマー。アスキー編集部時代にもフリーソフトを書いたりしていた。AMSCLS.INCという86アセンブラ用マクロセット(LHAのコードで全面的につかわれている)、親指シフトシュミレーターの親指ぴゅんなど。画像は、今年4月にbohemia氏がディープラーニングで生成してくれたもの。

Twitter:@hortense667

カテゴリートップへ

この連載の記事
ピックアップ