memoizeの甘い罠に悩む


 さて、memoizeである。メモ化とも言う。最初memorizeと間違えた。
 簡潔に言うと、重たい純粋関数はキャッシュしよう、である。
 平たく言い直すと、同じ引数を入れると必ず同じ物が返ってくるような関数なら、引数と戻り値で連想配列作ってキャッシュした方が速くなることもあるよね、である。まあ、やってる内容は昔ながらのソレである。

 Pythonの場合、モジュール変数は一度しか初期化されないので、実にキャッシュに向いている。しかも今触ってる鯖環境は、しばらくプロセスが生き続ける。もちろん変数も。実においしい。
 というわけで、重くて事前計算も不可能なものはmemoizeしたいのである。

 Pythonにはまた都合のいいことに、デコレータというものがあるのだが、memoizeをデコレータで書くならクロージャを使いたい気がするし、クロージャで縛った変数も鯖応答をまたいで保持されるのかいまいちよく分からんので、素直にモジュール変数を作って、重い関数内にキャッシュを直接実装した。

 テストランはしばらく調子が良かったのだが、どうも具合がおかしく、しばらく悩んだ末にようやく問題点を発見した。
 今回memoizeした関数はリストを返すのだが、Pythonのリストの代入は参照を代入する。戻り値を入れた変数をresultとすると、

cache[tuple(args)] = result

とか

cache[frozenset(kwargs.iteritems())] = result

とかでキャッシュに書き込んだ後、

return result

で終わる訳だが、それを受け取った呼び出し側がそのままリストを加工するとアウトな訳である。何てこったい。高級言語らしい罠だなあ。
 つーかどこもかしこもmemoizeデコレータってこんな感じの実装ばかり見るんスけど。ちくしょう油断した。
 というわけで、

cache[frozenset(kwargs.iteritems())] = list(result)

みたいな感じにコピーを書き込む仕様にした。直らなかった。
 まあ要するに、もう一ヶ所で全く同じ問題が起きていた。キャッシュヒットの時もコピーを返さないとね!
 つーか書き込みもlist()じゃなくtuple()にした方がいいな。それでもshallow copyだから、階層が深いならdeep copyが必要だなあ。

 まとめると、memoizeのキャッシュアクセスは全てimmutableかdeepcopyでなければならない、ってことだな。キーも値も。まあ、Pythonの連想配列のキーはimmutableが元々要求されるから、値だけ注意しろと。
 うーむ、単純ミスだ。参照代入な言語に触ってこなかったからか。むしろ値渡しのコピーコスト削減に必死だったしな…。まあ、参照だと認識してれば当然のバグな訳だが、抽象化の進んだコードにいまいち慣れてないな。C++とかはテンプレートをガシガシ書いてる時でもアセンブラマクロ目線だしな…。

 ところで、壮絶に久々に「りにとか」とかミスタイプして懐かしすぎた。何年ぶりかとか考えたくないものであるなあ。


FirebugとPythonでぐだぐだと


 Firefox使いがWebアプリ書くならFirebugが便利、みたいなのをちょこちょこ見掛けていたが、そこまで劇的に変わるんかなー、とか思って放置してた。デバッガってそんなには使わないし。プロファイラは超大好きだが。VSEEはそこが困る。買えってことだろうけど、開発しやすくした方がWindowsの防衛にもいいんじゃないすかね。

 で、原始的に開発していたが、どうも表示が崩れるバグに遭遇して、原因を探るのがかなり大変そうなので、試しにFirebugを入れてみた。
 控えめに言っても、想像の五倍くらいは上だった。何だこれスゲー。
 リクエスト、レスポンス、それぞれのGET/POSTパラメータ、JSONならデータ構造、DOMやスクリプトやCSSの構造、レスポンスからレンダリング終了までのイベント進行のグラフィカルなタイムライン、クライアントサイドのプロファイラ、と何でもかんでもあった。しかもCSSやHTMLはその場で属性を編集できて、リアルタイムに反映される。
 何つーかまあ、時代なんだろーなー。素晴らしいけど、進化が早すぎてきついな。
 ただし、表示が崩れるバグはDOCTYPEスイッチだったので、Firebugでは見付かりません。

 そんな訳で、サーバ側はPython一本でコーディングもデバッグもプロファイルもほぼ従来通りのスタイル、クライアント側はjQueryにプラグイン載せてコーディングしつつFirebugでデバッグとプロファイル、と。
 まあ、割と楽しいかも。

 つーかPythonも予想より遙かに楽しい。内包表記やイテレータに慣れた辺りから一気に。
 元々はPerlの感覚をベースにしてたから、mapとかgrepとか書きたい時が結構あって、map()やfilter()にlambdaを組み合わせたりしてた訳だが、内包表記で全部片付くのな。まあ、ワンライナー化しないようにはしたいが。
 イテレータも嬉しい。どうしてもリスト処理はオーバーヘッドが気になるし。そういえば変数の代入でも重いコピーが基本的に発生しないから、エイリアスとか関数切り分けとかが地味に楽かも。Javaとかも似た感じなのかね。
 本気出すなら、boost.pythonで簡単にC++モジュールも作れるらしい。本当なら素晴らしいですなあ。試してないから分からんですなあ。
 まあ、そこまで本気出すべきアプリを作る機会は当分無いかもしれんけど。ゲームとか、大きな往来が予想されるサービスとかなら、パフォーマンスは大事だろうけど。そりゃ作りたいっちゃ作りたいけど。


Python3.0仕様のrepr()が欲しかった


 Pythonは3.0で上位互換性を犠牲にして色々とすっきりしたらしい。ちょこっと見ると使いたくなる仕様ばかりだが、まあ、当面は2.5を使う必要があるので仕方ない。2.x系列も既に2.6が出て久しいっぽいけど。

 んで、とにかく読み込みの高速なシリアライズがしたかったのだが、Cライブラリは使えない環境であった。となると、一番高速なデシリアライザは何か。恐らくeval()だろう、素直に考えれば。入力元がAjaxとかだと大問題だが、そういうセキュリティ上の問題も今回は無い。
 であれば、eval()にそのまま渡せる文字列を生成してくれる組み込み関数repr()が最高に嬉しい、…はずなのだが。印刷不能な文字はエスケープされる仕様なんだけど、2.xだと大半が印刷不能という判定であった。つまり、日本語テキストとか全部エスケープされまくり。3.0から改善されたらしいのだが。うぬう。
 といっても、eval()に投げる分には問題は無く、単に人間が読めないだけなのだが、都合により人間も読みたいのだった。うぬーん。
 んで、仕方なくエンコード指定可能なrepr()もどきを自前で書いてみたら、あまりにも簡単に十数分くらいで出来て、動作的にも不満は無く、読み込みも超速かったのだが、どうももやもやするのであった。まあ、新版で解消されてるみたいだから文句を言う筋合いは無いし、古い環境を使わざるを得ない状況になっているのも仕方ない面はあるし…。早く3.0がもうバーンバーン使える世の中になるといいのにね!

 ちなみに自作repr()もどきは、ifを並べたくって、isinstanceとかで場合分けして、集合型はリスト内包の中から再帰させて、最後はelseの中にraise文、みたいなベタな奴だったけど、reprモジュールとやらを使えばさらに格段に簡単そうなことに後で気付いた。

 まあ、とにかく解決したからいいんじゃね。Pythonの練習にもなったし。


Pythonのクラスメソッドとスタティックメソッドで悩む


 スタティックメソッドって静的メソッドとも言いますよね。性的とか変換されて困るんですが。性的メソッド。悪くないな。

 で、あれだ。Pythonだとメソッドの第一引数に明示的にselfとか書く訳だが、それは全然苦にならない。元々そういう仕組みだろ的な。C++で常にauto thisとか書けと言われたら困るが。ちなみにselfじゃなくてthisでも何でも任意の名前で構わないようだが、まあ素直にselfと書こう。
 そんな俺も、selfを使わない時にまで書くのは別の意味で苦になる。つーか使われない引数は気持ち悪いし。
 そんな時はもちろんあれが欲しくなる。性的な奴。じゃなくてスタティックなメソッド。Pythonにもあるのかな。あったあった。クラスメソッドとスタティックメソッド。…二つもあるんですか?

 で、違いを調べる。クラスメソッドはクラスを第一引数clsに取る、スタティックメソッドは何も取らない、のか。はあ。いまいちわかんね。つーか継承した時、どのクラスにバインドされるん。
 試しに適当な基底クラスと派生クラスと普通のメソッドを作ってみて、クラスメソッドやスタティックメソッドに書き変えて挙動の違いを見てみたところ、どの種類のメソッドでも多態の挙動は同じだった。継承ツリーの探索過程が同じで、渡される引数だけ違うのかな。インスタンスを第一引数selfに与えるのが普通のメソッド、インスタンスのクラスを第一引数clsに与えるのがクラスメソッド、引数を追加しないのがスタティックメソッド、か。多分。
 で、何の為に分かれてるんだろう、これらは。

 適当に調べてもいまいち分からんので、仕方なく英語で検索。すぐに出てきた。ちくしょう英語め。
 英語様によると、インスタンス変数に触るなら普通のメソッド、クラス変数だけ触れればいいならクラスメソッド、その辺に全く触らなくていいならスタティックメソッド、とのこと。
 ああ、最初に自分で思ってたじゃん。self要らない時は書きたくない、って。
 つまり、selfもclsも要らないなら、selfもclsも書かないスタティックメソッド。self要らないけどcls要るなら、clsを書くクラスメソッド。self要るなら普通メソッド。くそう。簡単な話じゃないか。

 まあ、本当にこれでいいのかは知りませんが。
 とりあえず、基底クラスのメソッドAから別の多態なスタティックメソッドBを呼び出す、みたいな使い方はちゃんと動いてるようだが。


XHTMLとかHTML5とかbrタグとか


 brタグありますよね。HTMLの。改行するよ的な。
 あれ、XHTMLだとXMLの規則に従うから、<br />とか書く訳で。綺麗といえば綺麗、でも融通利かないといえば利かない、でもまー別にどっちでも不満は無いな、とか思ってた。ただ、<br />じゃなくて<br/>とスペース無しで書くのは駄目なんかなー、とも思ってた。
 で、ついさっき別の用でXML仕様を読んでたら、何だよ、<br/>でもいいんじゃん。
 さらに、HTML5だと<br>でいいとかいう。DOCTYPEも超短くなってるし。XMLでもSGMLでもないからいいのか。まあ別にブラウザ的にも困らんだろうし。
 HTMLのおきらく感とXHTMLのカチカチ感が何だかPerlとPythonを思い出すが、プログラム言語でもないんだから、統一感が無くても良きに計らってくれるHTMLの方が好みかなあ、とは思った。
 プログラミングでは今のところPythonがすごく楽しいけど。「書き終わって走らせたら一発で動いてすごく不安」という例の謎心理も久々に経験したり。言語に慣れるにつれて無くなってくるんだよなあ、これ。まだ分からないけど、たぶんカチカチ感も気に入ってると思う。