MicrosoftがExcelにPythonを搭載することを真剣に検討しているらしい。
www.itmedia.co.jp
まだ検討の段階なので、どんな実装になるかは明らかにされていないが、基本的にはVBAと同じくCOMの操作になるんじゃないかと思う。
今回はひと足先に、PythonでCOMを利用したExcel操作をやってみようと思う。
参考にしたサイトはこちら。
Python Win32 Extensions - MyMemoWiki
COMとは
COMとは「コンポーネント・オブジェクト・モデル」の略で、様々なプログラミング言語から呼び出すことができるソフトウェア部品の技術仕様として1997年にMicrosoftが発表したものである。
.NET登場以前はWindowsの標準的な技術であり、現在も数多くのソフトウェアがCOMに依存している。
COMではオブジェクトをメモリにどういう風に配置するか、自身が持つプロパティやメソッドを呼び出し元にどうやって伝えるかといった細々とした仕様が取り決められているので、COMの仕様に従った部品は様々な言語から利用することができる。
Excel VBAも、実はVBA言語でExcelのCOMオブジェクトを操作する行為であり、例えばRange("A1").Value = "Hello"という命令はVBAというよりも、ほぼCOMの操作に近い。
厳密にいえば、以下の特徴はCOMではなくVBAの仕様である。
- イコールで代入する
- オブジェクトのプロパティにはドットでアクセスする
- 文字列はダブルクォーテーションで囲む
- 大文字、小文字を区別しない
ただ最初の3つは多くの言語で採用されているので、Pythonで書いてもJavaで書いてもRubyで書いても、Range("A1").Value = "Hello"となる。そうでない言語もあるかもしれないが。
さて、では実際にExcelを操作してみよう。
先ほどバージョン確認のためにPythonを起動したが、これはexit()を入力して終了させて、再度pythonコマンドで起動しておく。
また、起動しているExcelがあれば終了させておいたほうが分かりやすい。
そして、入力待ちのプロンプト「>>>」が表示されたらimport win32com.clientと入力してEnter。
>>> import win32com.client
これは先ほどインストールしたPython Win32 Extentionsを読み込むための命令で、成功すれば単に次の入力プロンプト「>>>」が表示される。
他にズラズラと表示されてたらエラーなのでスペルミスがないか、インストールに成功しているか再確認する。
次に、変数xlAppにExcelを代入する。
>>> xlApp = win32com.client.Dispatch("Excel.Application")
ややこしい操作だけれど、VBScript のSet xlApp = CreateObject("Excel.Application")に相当する操作だと思っていだけると良い。
Pythonには変数宣言が存在しないので、単に変数名に値を代入するという操作になる。
また、VBAの場合はオブジェクトの代入にはSetを使うが、Pythonは数値や文字などと同じく単に代入するだけである。
さて、この段階でExcelがバックグラウンドで起動されているが、画面上はまだ表示されていない。
次に、Excelを表示させる。
>>> xlApp.Visible = -1
xlAppはExcel VBAのApplicationと同じように扱える。VBAの場合はApplication.Visible = Trueと書くが、VBAではTrueの値が-1なのに対し、PythonではTrueの値が1なので、ここでは-1を指定している。
ただVBAは0をFalse、0以外をTrueと判定するので、xlApp.Visible = Trueと書いても動作する。以降は分かりやすいようにPythonのTrue、Falseを使って書く。
さて、ここまで来たら、基本的なCOM操作はVBAと変わらない
ワークブックを追加してシート名をSampleに変え、A1セルにHelloと入力してクローズする処理をやってみる。
>>> wb = xlApp.Workbooks.Add()
>>> sh = wb.Sheets(1)
>>> sh.Name = "Sample"
>>> sh.Range("A1").Value = "Hello"
>>> xlApp.DisplayAlerts = False
>>> wb.Close()
>>> xlApp.DisplayAlerts = True
>>> xlApp.Quit()
コマンドを入力してEnterするたびに、処理が実行されるのが分かる。
ちなみに上記の処理をVBAで書くとこうなる。
Set xlApp = Excel.Application
Set wb = xlApp.Workbooks.Add
Set sh = wb.Sheets(1)
sh.Name = "Sample"
sh.Range("A1").Value = "Hello"
xlApp.DisplayAlerts = False
wb.Close
xlApp.DisplayAlerts = True
xlApp.Quit
VBAとPythonの違いを見てみると、
- オブジェクトの代入にSetをつけるかどうか
- 引数のないメソッド呼び出しに()を付けるかどうか
という2点を除いて、あまり変わらない。
つまりCOMである以上、オブジェクトの操作感はそれほど変わらないということになる。
ではPythonだと何が嬉しいのかというと、豊富なライブラリ群と洗練された言語仕様である。
Pythonの機能を使ってマクロを作る
折角なのでPythonのライブラリを使ってExcelマクロを作ってみよう。
サンプルなのでVBAでも簡単にできるような内容にしておく。
>>> import win32com.client
>>> import datetime
>>> xlApp = win32com.client.Dispatch("Excel.Application")
>>> xlApp.Visible = True
>>> wb = xlApp.Workbooks.Add()
>>> ws = wb.Sheets(1)
>>> now = datetime.datetime.now()
>>> ws.Range("A1").Value = now.hour
これは最初にPythonのdatetimeライブラリを読み込んでおき、変数nowに現在日時を入れて「〇時」だけを取り出すマクロ。
Pythonのdatetime型はオブジェクトなので、hourプロパティで時刻を取り出すことができる。
ブログ執筆時点では夜9時なので、A1セルには21が挿入される。
VBAならNow()関数とHour()関数を組み合わせるところだが、こちらはVBA専用の関数なのでPythonからは利用できない。
またCollectionもVBAライブラリのクラスなのでPythonからは利用できない。
※VBA自体もおそらくCOMなので、PythonからVBA関数を利用する方法はあるかもしれない。
更に、配列などのデータ型や、IfやForなどの構文もVBAとは異なる。
共通しているのはあくまでCOMの操作部分だけである。
for文を例にPythonの特徴を紹介
実はPythonにVBAのようなFor文は無く、VBAでいうところのFor Eachが標準のfor文にあたる。
たとえば1から10まで出力させたい場合、VBAでは次のように書く。
For i = 1 to 10
Debug.Print i
Next
Pythonではこうなる。
>>> for i in range(1, 11):
... print(i)
...
ここでrangeはpythonの関数なのでExcelのRangeとは関係ないことに注意。
1~11を指定するとひとつ少ない1~10が作られるという、VBA使いには馴染みのない仕様である。
この...は>>>と同じく前行から続いているという意味のプロンプトなので自分で入力する必要はない。
for文の最後は必ずコロンを入力して改行する。そしてTabキーでインデントし、print(i)と入力してEnter。
これで終わりなら、プロンプト「...」でそのままEnterを入力すると1~10まで出力される。
また、VBAではブロックを開始と終了のステートメントで表すのに対し、Pythonではインデントで表す。
コードの見た目がそのまま文法になってしまうので自由にインデントすることはできない。
これにはスタイルの違いによる読みにくさが発生しないというメリットがある。
さて、では最後のサンプルとしてPythonのforでVBAのFor Eachと同じようにセルに対して使ってみよう。
次のコードを実行するとA1からA5にそれぞれHelloと入る。
>>> for r in ws.Range("A1:A5"):
... r.Value = "Hello"
...
これでCOMの操作は同じであるが、標準関数や文法が異なるということがお分かりいただけたかと思う。