python のローカル変数のスコープと functools.partial
今日のネタは、ちょっとミスって python でエンバグしてしまったので、自戒の意味を込めたメモです。
失敗コードは下記のようなものです(無関係の所はごっそり削ってます)。 引数 e や n の値に応じて、 go に関数オブジェクト (か None) を設定しています。
def in_stage(e=None, n=None): go = None if (e != None): go = lambda: goto_event_stage(e) elif (n != None): go = lambda: goto_normal_stage(n) ...(実際の処理本体。途中で go() を使う)...
これ、何が悪いかというと、下のほうの処理本体部分で e や n を変更してしまうと、goを呼んだ時の挙動が変わってしまうんですね。
# 関数の引数が n=3 だった場合 go() # goto_normal_state(3) が呼ばれる n = 100 # でも途中で n を変更してしまうと go() # goto_normal_stage(100) が呼ばれる
この現象は lambda 式ではなく、def による名前持ちの関数であっても起こります。
原因と対処法
GUI自動操作ツール Sikuli を Ubuntu 11.10(Oneiric) にインストール
Sikuli は、デスクトップアプリケーションを自動操作するためのツールで、ボタンの画像をキャプチャしておいて画像認識で操作するという、独特ですが直感的なスクリプト体系が特徴的なツールです。
例を見れば一目瞭然なので、サンプルとして、Chrome の特定のプラグインを無効化するスクリプトを書いてみました。
「スパナのアイコン」→「設定」→「拡張機能」と順にクリックし、特定のアイコンを探して、その右に「有効」となっているチェックボックスがあれば、それをクリックして、最後に設定タブを閉じる。……と、若干複雑な事をさせていますが、それなりに直感的に読めたのではないでしょうか。
今日のエントリは、この sikuli を ubuntu 11.10 (Oneiric) にインストールする作業のメモです。Ubuntu 12.04 のリリースを控えた今のタイミングでは、非常に賞味期限の短い記事になりそうですが、備忘録として書いておきます。
Ubuntu 11.10 での状況
python で Google Quine を再現させてみた
先日(といっても2ヶ月以上前ですが)参加した Google Code Jam Japan 2011 ですが、おかげさまで入賞することが出来、右の写真の通り、記念Tシャツを頂くことが出来ました。主催された方々、参加された皆さん、楽しい時間をありがとうございました。
ところで、このTシャツにプリントされたAAですが、これは ruby のスクリプトになっていて、これを実行すると自分自身のソースコード(つまりこのAAそのもの)を出力するという変わった性質をもったコードになっています。このようなプログラムのことを quine と呼ぶのだそうで、このTシャツのコードの作りかたは、Code Jam Tシャツについてに詳しく書かれています。
今回は、この Google Quine を ruby ではなく python で再現させてみよう、というネタです。
(余談ですが、このTシャツを受け取ってネタを思いついた翌日にはがっつり時間をかけてコードを完成させていたのですが、ブログのエントリへのまとめは2ヶ月も放置していたという……)
目標とするのは
- きちんと Quine になっていること
- 元ネタと(可能な限り)同形であること
- 元ネタと同等の機能(HTMLカラー出力オプション)を持っていること
です。
Python をご存知の方は判ると思いますが、Pythonはこのようなコードを書くのには全然向いていない特徴を持った言語です。やる前はかなり無謀な気がしていたのですが、いざやってみたらなんとかなってしまって、機能拡張も出来てしまいました。
今日の記事は完成品の紹介と、このネタをやるうえで障害となったPythonの特徴やそれに対するテクニックの紹介の紹介です。
完成品
先に完成形を出しておきましょう。こんなかんじです。
\ q='''f=l ambda (l,r),(p,m):( l+d(m )+r[: p],r[p :]); v=(_ _im port __(' s ys') .arg v+[0])[1 ];c=chr; s=c(32); n=c( 10);y=x TM =c(9 2);l=c(60) ;g=lambda( n):c(27)+' [%sm '%(n+30*( n!=0 ));d ,t=( (lam bda( n): '',' '),( g,' '),(l ambd a(n) :l+' fon t'+s+'co lor =%s> '%['black ','r ed','g ree n','yell ow' ,'b lue '][n ],l+'pr e>') )[(v=='-h') *2+ (v= ='- e')] ;pri nt(t +y+ n+red uce( f,z ip(( 20,1 4,13 ,11,7,11 ,3), (4,1 ,3,4, 2,1, 0))* 15+[( 990, 4)], ('',s *8+' q='+" '" *3+q+"'"*3+";" +s*6+"8;" +y+n+s*46 +"exec" +s*6+ "(''"+n+ s*47+"+''.j oin(q ."+n+s *48+"split ()))" ))[0]+ d(0)) ;88; '''; 8;\ exec ('' +''.join(q. split()))
このコードは Python 2.x用です。元ネタと同様、そのまま実行で自分自身を出力し、引数に-hを渡すと色付きHTMLで出力されます(元ネタみたく大量のタグを出したりしないので、Firefoxでもきちんと表示できます)、ついでに、-eでANSIエスケープシーケンスによる色付きテキストを出す機能も付けました。
形に関しては、1行目のバックスラッシュ1文字以外は元ネタと完全に一致するようにしています。それぞれの機能確認方法はこんなかんじ:
(元ネタと同様、quine となっているか) $ diff -u google_quine.rb <(ruby google_quine.rb) $ diff -u google_quine.py <(python google_quine.py) (元ネタと同形になっているか) $ diff -ub <(sed 's/[^ ]/x/g' google_quine.py) <(sed 's/[^ ]/x/g' google_quine.rb) (HTMLの出力が出来ているか) $ python google_quine.py -h > tmp.html $ firefox tmp.html $ diff -ub google_quine.py <(w3m tmp.html) (エスケープシーケンスでの色付けが出来ているか) $ python google_quine.py -e $ diff -u google_quine.py <(python google_quine.py -e | sed "s/\x1b[^m]*m//g")
インデントに意味がある
Make: Tokyo Meeting 07 に行ってきました
今日は、オライリー主催のもの作りイベント、 Make: Tokyo Meeting 07 (@東工大 大岡山キャンパス)に行ってきました。
時間が無かったため、じっくり話を聞けたのは体育館展示の一部だけでしたが、せっかくなので、きょうお話を聞けた所をご紹介します。
明日もやっているので、興味を持たれた方は行ってみてはいかがでしょうか。
O'Baka Project(@kimio_kosaka)
送信者 2011-12 MTM07 |
ビン詰め回路。ボトルシップを電子回路でやっちゃいました、という作品。
え? どうやってるの? と気になった方。是非、教わりに行ってみて下さい。
秋山純司研究室(秋山純一・迎山和司)
送信者 2011-12 MTM07 |
ヒカリモノがあって技術的にも面白いものがいろいろ置いてあるのですが、地味に目を引いたのがコレ。物凄く奥に長い穴のように見えて、じつは薄っぺらい。写真ではなく実際に見るとインパクトがある良い例ですね。
TEK NOK PHALIJA 現象-発見 変換装置 TATAN
送信者 2011-12 MTM07 |
電池や抵抗、銅線などがアクリル版のピースに埋まっていて、それをジグソーパズルのように組み上げると、回路が出来て抵抗が発熱する。……だけでなく、電気の流れる様子や、「発熱してますよー」感を出すアニメーションが表示されるというシステム。どういう原理かは会場で聞いてみよう。
e-lab works
送信者 2011-12 MTM07 |
うねうねとヘビや魚のように身をくねらせながら進むロボットです。見た目ではわからないかもしれませんが、付いているタイヤは全部、動力を持たないタイヤで、「縦方向にはスルスルと空転するが、横方向には抵抗がある」というタイヤの特性を器用に使って前進します。
明日 12/04 もやってます
まだまだ見てきた物は沢山あるのですが、書き出すのが面倒になっt
ぜひとも実物を見て欲しい物ばかりですので、もし、明日、お時間があるようなら、会場に足を運んでみてはいかがでしょうか。
Google Code Jam 向け python template
明日は Google Code Jam Japan 2011 本戦です。
予選はなんとか突破できたので、Tシャツ目指してもうひと頑張りしてみます。
予選の前日にpython 向けテンプレートを公開しましたが、いざ予選で使ってみると、若干不満が残ったので修正してみました。修正箇所は以下の通りです。
- 便利なライブラリを幾つか import
- "-m" でマルチプロセス処理時に Ctrl + C で止められるようにした
- "-q" を付けると、print 文による画面出力を抑制できるようにした
- solve_xxx のような名前で複数の solver を実装しておいて、"-c"を付けて実行すると、それぞれの solver の出力を比較して相違が無いかを確認してくれるようにした
最後の奴は、「とりあえず small を力技で解く」とかやってしまった場合用です。
この場合、作りなおすなりリファクタリングするなりして、Large に耐える解答を作らなければならないわけですが、smallを正解できた solver を solver_small とでも rename しておけば、作りなおした関数が間違っていないかは -c を付けるだけで確認できるわけです。
まあ、いろいろ小細工を足してみましたが、最初から素直に正しい解答が書ける人なら無用の長物ばかりですね。orz
続きを読むCode Jam Japan 2011 報告
昨日書いた Google Code Jam Japan 2011 の予選が先程おわりました。
問題サイズに対する見積りがあまくて、最初の2問の Large を速攻で落とすという痛い失態をかましてしまい、3問目だけは慎重に解いてなんとか正解して本戦に残ることが出来ました。
Large は提出期限が切れた後も解き続け、予選終了後の演習モードで再提出してみたら、ちゃんと正解できましたので、本番もそのくらい慎重にやれ、ってことですかね。
とりあえず、(ちゃんと解いたんだぞ、という証明代わりに)全3問の解答と解説をこちらに貼っておきます。(あ、昨日貼ったテンプレートを使用しているので、実際に問題を解いているのは solve 関数の中だけですよ。)
あとで解いてみようと思っている人は、以下は読まないように注意!
(2011-10-02 追記: ちゃんとデキる人が書いてくれている解説を見つけたので、参考にする人はそちらをどうぞ → 不確定な Android Blog - Google Code Jam Japan 2011 予選終了 )
続きを読む