2008年10月27日月曜日

[pyspa]Python温泉おつかれさまでした

普段Blogを愛読しているこの人に会えたのでちょっと嬉しい
アクセンスの中の人からPythonぬいぐるみをいただきました
本物のHackerとはどういう人種か、大変勉強になりました
っていうかアクセンスすごいよアクセンス ← 今の今までどういう会社か知らなかった

Python温泉、2泊3日お疲れ様でした。無線LAN完備の温泉完備の布団完備(?)の食料完備で大変有意義な時間を過ごすことが出来ました。本物のHacker集団はバイタリティがすごい。ニコ動の(正確にはニコニコ大百科の)中の人とお話しできたり、実は毎日自分がクレクレ厨をしていた相手が取締役と社長さんだったりとあとから思い返せばなかなか冷や汗ものでしたが、まぁ旅の恥はかきすてっていいますから・・・駄目?

一番勉強になったのは「徹底的な探求心」、感じ取れたのは「集中力」、自分に必要なのは「現在の環境に対するチャレンジ」。たとえばEclipseをやめてVimとEmacsでPythonを書いてみたりとか。

2008年10月26日日曜日

第4回Python温泉 参加中 3日目

- 9:00
おはようございます・・・
テキストエディタをmiからSmultronに入れ替えてみました
制御文字を表示したときの半角スペース表示があまりにも汚いところ以外は最高です。
でもemacsとかviも使えないと困ると思いました

- 9:47
朝早いです・・・
とりあえず家に帰ってからやるべきTodoリストを作成しておきます。

MacPortをインストール、GUIもあると便利なのでインストール
http://komposition.jp/2007/09/porticus/

MacPortからnmapをインストールする

JSONをevalして意地でも画面に出す

2008年10月25日土曜日

第4回Python温泉 参加中 2日目

- 8:00
起床。眠い!

- 9:00〜11:00
持ち込んだカルドセプトDSが大活躍してくれました。

- 11:20
温泉でさっぱりしたところで仕事開始。
まずは昨日のまとめを行う。増田さんと俺の違いは何?何を改良すればあのように優れたハッカーになれるか?

- 12:00
お昼ご飯を食べながら会社の仕事をやったりメールチェックしたりRSSをチェックしたり

- 13:00
来宮神社まで遊びにいく、神社まで遊びに行くというと、某吸血幼女が頭に浮かんだりするがいっさい関係ないと思います

- 14:23
神社に行く予定がなぜか途中の有名人の別荘に足を取られて1時間以上ガイドの人のお話を聞くことに・・・
遅れている仕事を取り戻す

- 16:05
django.conf.globalsettings.py

# List of processors used by RequestContext to populate the context.
# Each one should be a callable that takes the request object as its
# only parameter and returns a dictionary to add to the context.
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
# 'django.core.context_processors.request',
)
django.core.context_processors.mediaがメディアファイルのURLをテンプレートに渡されるコンテキストに勝手に渡してくれる
strutsに例えるならば、request.setAttritebute()を勝手に裏でやってくれるところ
ここで、
    return {'MEDIA_URL': settings.MEDIA_URL}
としているので、テンプレートの中でMEDIA_URLが使えるはず。使ってみよう

- 20:03
4時間ぐらいずっとdjango.views.static.serve()について悩みっぱなし。
設定は絶対に間違っていないはずなのに、staticファイルが何度やっても読み込めない・・・なぜ?
こんなエラーが出る:
Page not found: /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/contrib/admin/media/css/django_todo.css
一体全体どうしてdjango/contrib/adminなんて所を見ているのかどうかわからない・・・

- 20:10
増田さんありがとう(またかよ)!
つまりはこういうことでした。settings.pyの以下の行が原因。

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
# MEDIA_URLやdjango.views.static.serveのdocument_rootと同じ値を設定すると、
# django.adminの要求するパスとかぶってしまうためうまく動かない!
ADMIN_MEDIA_PREFIX = '/media/'
#ADMIN_MEDIA_PREFIX = '/admin_media/' のように書き換えればうまくいくことがわかりました
これでなんとか先に進めそうだ!ラストスパート!!

- 23:19
無事にJavaScriptとCSSを参照することに成功するものの、こんどはUnicodeとJSONではまってしまう・・・
1:'\u71c3\u3048\u308b\u30b4\u30df\u3092\u51fa\u3059\u7528\u610f\u3092\u3059\u308b'こんな感じの文字列で画面に送られてきてしまう。日本語として出したいのだが・・・
2:そもそもJSONがeval()できない!
eval('{a:b}');
これを実行するとエラー・・・

1時間近く格闘して解決。まず1については、これは評価されていない素のユニコード文字列だから。これをそのままtext/plainとして画面に出しているから記号のまま画面に出てしまうようだ。Python側でこれをどうこうすることはできない(Unicodeとして正しいから。出力時に勝手にきちんとした日本語にされる訳で、データとしてはユニコードとして正しい。u'\u71c3'とu'燃'は全く同じ。)解決するためには、いったんこの文字列をJavaScriptでevalして評価してもらう必要がある。

2については、そもそもJSONとして形式が間違っている。
プロパティ名と値はクオテーションする必要がある。
eval('{"a":"b"}');
これが正しい。しかしこれでもエラーになる。なぜか?
http://d.hatena.ne.jp/language_and_engineering/20081022/1224597688
このページをみて解決。まさに書いてある通り。
全体を括弧で囲まないと、"a"がジャンプ用ラベルとして扱われてしまう。括弧で囲めば{}以下がオブジェクトとして扱われる。
ということで、正解はこう
eval('({"a":"b"})');
JSONでやたら括弧が多い理由がやっとわかった!!
それにしても、たかがJSONと思って驕り高ぶっていたらひどい目にあった・・・己の無知を痛感。

2008年10月24日金曜日

第4回Python温泉 参加中 1日目

- 11:40
宿に到着、こんなに坂の上とは思わなかった

- 12:30
近くの来宮神社でうどん、なかなか美味しい
雨が降っていなければまたきて写真撮ろう

- 13:00
RTMにアクセスするだけの簡単なDjangoアプリを作ってみることにする
http://www.rememberthemilk.com/services/api/
http://repo.or.cz/w/pyrtm.git
こいつのソースを解析してRTMへのアクセス方法を調べる予定、まずは後回しにしてdjango側からつくってゆく

- 14:00
全員黙々とプログラミング作業中、なんだか会社にいるときよりまじめに仕事している俺がいる
さすがにこの空気で遊ぶ訳には・・・

- 15:42
なんとかURLとviewの設計まで完了、まだHelloWorldレベル
Modelは全然使ってないです^^

誰でも知っているどうでもいいTips:
Mac OS Xのpythonのインストール先はなんだか特殊なのでwhichして調べよう
   akisute bin$ which python
/Library/Frameworks/Python.framework/Versions/Current/bin/python
akisute bin$ cd /Library/Frameworks/Python.framework/Versions/Current/bin/python

2行目をコピーして、/bin/pythonを/libに書き換えるといい感じ。/lib/python2.5/site-packages以下がみんな大好きサイトパッケージです
後々の実験のために、ここのsite-packagesにrtm.pyをおいておく

- 16:03
そろそろRTMへのアクセスが必要なので、rtm.pyの解析を行うことにした
パブリックメンバーとして用意されているメンバーは4行目に定義されている
   __all__ = (
'API',
'createRTM',
'set_log_level',
)

あとtest()も自由に使えるようだ。
どうやらcreateRTM()すれば基本万事解決みたいですね。
ここでapiKey, secret, token, frob, signといったよくわからない単語が多数登場。RTMのAPIリファレンスをみて勉強し直すことにする

- 16:50
WireSharkなるソフトウェアが話題になる。
(パケット監視ソフトウェアらしい)
Mac OS XではCocoa動作ではなくてX11(多分GTK)で動作するとのこと
・・・こんなのを使うのかよ

- 17:22
RTM APIシステムについて調査完了。別記事にして詳しく書きます。腹減った・・・

- 18:12
温泉に入ってきました。さすが源泉掛け流しだぜ・・・いい湯でした

- 18:42
rtm.pyの使用により、RTMからタスク一覧を取得することに成功!
しかしrtm.pyが例外を吐いて止まってしまいました。
Traceback (most recent call last):
File "", line 1, in
File "rtm.py", line 381, in test
print [t.name for t in rspTasks.tasks.list.taskseries]
AttributeError: 'list' object has no attribute 'taskseries'
ソースを追ってみると・・・384行目
rtm = createRTM(apiKey, secret, token)
rspTasks = rtm.tasks.getList(filter='dueWithin:"1 week of today"')
print [t.name for t in rspTasks.tasks.list.taskseries]
さらに追いかける・・・85行目から
def get(self, **params):
"Get the XML response for the passed `params`."
params['api_key'] = self.apiKey
params['format'] = 'json'
params['api_sig'] = self._sign(params)
json = openURL(SERVICE_URL, params).read()
LOG.debug("JSON response: \n%s" % json)
if _use_simplejson:
data = dottedDict('ROOT', simplejson.loads(json))
else:
data = dottedJSON(json)
rsp = data.rsp
if rsp.stat == 'fail':
raise RTMAPIError, 'API call failed - %s (%s)' % (rsp.err.msg, rsp.err.code)
else:
return rsp
rsp.statにはアクセスできるが、
rspTasks.tasks.list.taskseriesにはアクセスできない・・・
返ってきたJSONをよく見てみる
{"rsp":{"stat":"ok","tasks":{"list":[{"id":"3161896","taskseries":{"id":"......
なるほど、listがリストになっている。
rspTasks.tasks.list[0].taskseriesというふうにしなくちゃならないんだな。

- 21:26
ご飯も食べ終わってそれでもひたすらソースを書き続ける・・・
引き続きDjangoのview作成を進めるが、rtm.pyの結果をJSON形式にできないことが判明(DottedDictという特殊な型)
自分でJSON変換を書くしかないのかな?オブジェクトをJSONに変換するライブラリなんていくつもありそうだけど

それからもう一つ問題が、
Djangoのデバッグ時のエラー画面(エラーの詳細情報を表示してくれる)がうまく表示されない。

TemplateSyntaxError: Caught an exception while rendering: unknown encoding: X-MAC-JAPANESE

- 22:34
増田さんがあっというまに問題を解決してしまいましたとさ・・・
かろうじて何をやっているのか見えた箇所をメモ
find -r? ./ -name 'sitecu*.py'
C Pythonを使ってC言語のstdlibのlocaleモジュールにアクセス?
QuickSilverを利用?
export LANG=ja_JP; python
>>> import sys
>>> dir(sys)
>>> sys.getdefaultencoding()
>>> import locale
>>> print locale.getdefaultlocale()
>>> assert False, locale.getdefaultlocale()
>>> print '\n'.join(sys.path)
python -vで読み込まれたパッケージがすべて表示される
/usr/local/bin以下のシンボリックリンクをdmgパッケージからインストールしたPython.org公式のPythonが上書き(というか優先的に読み込み)している
結論から:
1:python.org公式の2.6にアップグレードする。問題が修正されている。
2:/System/Library以下のPython2.5.1を利用する、Macシステム標準のPythonはMacPortsから大量のパッチがあたっているらしい。
公式の2.5.2はそれらのMac用のパッチがあたっていないためそのような問題が起きる・・・?
(Cocoaを利用してロケールを読み込んでいるから?envを無視している?)
3:どちらもいやなら、sitecustomize.pyを作って修正を書き込む

よくわからないがとにかくpythonを2.6にアップグレードするのが最善なようだ。

- 0:46
python2.6へのアップグレードは問題解決にならなかった。
確かにパッチはあたっていたが、locale.getdefaultlocale()の値を書き換えるようなパッチではなく、
getdefaultlocale()の値がX-MAC-JAPANESEの場合はsjisに振り返るようにしているだけで、
直接locale.getdefaultlocale()の値を利用しているdjangoの場合には使えないようだ。

locale.getdefaultlocale()が正しい値を返すようにするにはAppleがビルドしたpython(パッチ適用済み、要するに2.5.1)を使うしかない。

そこで回避策を考えつかれた:
エラーで落ちる原因はX-MAC-JAPANESEを処理するためのcodecが登録されていないから見つからないでLookupErrorになっている
X-MAC-JAPANESEの正体は単なるshift-jisなので、shift-jisのコーデックを利用して新たにX-MAC-JAPANESEのコーデックを登録すればいいということらしい。

あっというまにパッチが完成、試してみると・・・見事に通った!これがハッカーの仕事か・・・

あとFinderで隠しファイルを表示したり/usr/binを表示する方法が地味にわかった
http://goonsh.ddo.jp/fg/2005/01/18/on-finder
http://netafull.net/macosx/014755.html

Spotlightの有用性もわかった
明日はQuickSilverを入れてみることにする

今日はもう寝る!!

よくわかるユニコード

  • Unicodeは文字コードセットのこと。UTFとは別。
  • UTF-何々というのはUnicodeをのエンコード方式のこと。
  • BOM(Byte Order Mark)は基本的にUTF-16にしかつかない。UTF-8では不要。
近頃はWeb上のリソースから、iPhoneの文字列までみんなUnicodeになりましたね。
でもよく考えたらUnicodeについて真面目に学んだことが一度もなかったので、BOMのあるなしで悩んだのをきっかけに、Unicodeについて勉強してみました。

勉強しただけではすぐ忘れちゃうので、こんな図にしてみました。




これで少しは覚えられるかも。

2008年10月16日木曜日

Pythonで変数の型をチェックする方法(Javaでいうinstanceofが使いたい)

  • リスト、辞書、タプルのようなイテレータが使える型には__iter__属性がある
  • ただし文字列には__iter__がない
  • Javaでいうinstanceofがやりたいときは、組み込み関数isinstance(obj, type)を使う
  • issubclass(obj, type)というのもある
基本的にPythonではあまり変数の型を気にしないようなのですが、
それでもどうしても型チェックがやりたくなるときはあります。
引数が本当にリストなのかどうかチェックしたりとか、引数をfor()文でループさせたいときとか。
そういった場合にPythonではどうすればいいのか調べてみました。
以下、すべてPython2.5.2で動作確認しています。

Javaでいうinstanceofに相当するPythonの組み込み関数はisinstance(obj, type)です。このメソッドを使えば、引数がリストか、文字列かといったチェックは簡単にできます。
#listかどうか
isinstance([1,2,3], list)

#辞書かどうか
isinstance({'a':1, 'b':2}, dict)

#タプルかどうか
isinstance((1,2,3), tuple)
引数がiterableかどうか(for文でループできるかどうか)の判定はちょっと複雑で、以下のようになります。
#itarableかどうか(Stringを含む)
#実際にはgetattr(obj, '__iter__', False)よりもhasattr(obj, '__iter__')のほうがスマート
isiterable = lambda obj: isinstance(obj, basestring) or getattr(obj, '__iter__', False)
isiterable('abcde')

#iterableかどうか(Stringは含まない)
getattr([1,2,3], '__iter__', False)
#またはhasattrを使って
hasattr([1,2,3], '__iter__')
普通のiterableなオブジェクトは__iter__属性を持っているのでこれですぐに判断できます。
しかしなぜか文字列だけは__iter__属性がないのでisinstance()を併用します。

※一部http://bytes.com/forum/thread514838.htmlより転載いたしました。ありがとうございました。

2008年10月13日月曜日

Android チュートリアル: Notepad Exercise 1

  • AndroidアプリではSQLite3がデータベースとして利用できる
  • 基本的なデータベースに対するCRUDのためのヘルパーメソッドはあるが、DDLはSQLリテラルを定義して投げる必要があるようだ
  • O/Rマッパーは標準では装備していない
  • /res/ディレクトリ以下にXML形式の設定を沢山並べると、R.javaクラスが自動的に更新される
  • チュートリアルのアプリにはメモリが漏れるバグがあるので修正してみた
Android SDKのノートアプリケーションを作るチュートリアルをやってみたので、普通のJavaアプリと異なる点やAndroid開発で独自な点などを挙げてみます。

■データベースアクセス
AndroidのアプリではSQLite3がバックエンドデーターベースとして使用できるようです。データベース名とテーブル名を指定してデータベースを作成することが出来ます。
他のAndroidアプリが使用しているデータベース名と同じ名前をデータベース名として指定したときの挙動は未調査です。おそらくはセキュリティの観点上分けてあるはず(他のアプリのデータベースに勝手にアクセスできるのはいくら何でもまずい)・・・だとは思うのですが。

その他、Content Providerという他のアプリと共有できるデータソースが用意されているようなのですが、こちらは後ほど。今はまだ未勉強。

データアクセスの方法はSQLiteOpenHelperクラスでSQLiteDatabaseオブジェクトをopenして、このオブジェクトを使ってSQLiteにアクセスするようです。基本的なCRUDアクセスはすべてメソッドとして提供されています。
ただしDDL(Create TableとかDropとかAlterとかTruncate)はすべて手打ちのSQL文字列を投げて実行するみたいです・・・
Create Tableまで手打ちなのがちょっといただけない感じですね。O/Rマッパーは標準装備されていないのでしょうか?深く調査したわけではないですから何とも言えませんが、やはりリソース的にO/Rマッパーは重くてキツイ?

■XMLによるビューと文字列のリソース定義
ここが普通のJavaアプリと一番異なる点かな。/res/ディレクトリ以下でXMLを定義すると、R.javaというクラスファイルが自動的に生成されたり更新されたりします。
このR.java内の定数定義を用いてJavaソース上でXMLリソースを指定するというのが、Android(のActivity)開発でもっとも特異な点に思えます。たとえばこんな感じ。
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.notepad_list); //ココ
  mDbHelper = new NotesDbAdapter(this);
  mDbHelper.open();
  fillData();
}
不思議な感じですが一度慣れると病みつき。定数で定義出来るというのが便利。普通はsetContentView("R.layout.notepad_list")みたいに文字列で指定するのが一般的だと思いますが、これだとミスタイプしてもコンパイルエラーにならないし、何よりEclipseの入力補完が効かない。

で、XMLファイル自体の書き方もちょっと癖がある。たとえばandroid:id属性値の指定の仕方。
ListView id="@android:id/list"
TextView id="@android:id/empty"
このように@android:を使って指定すると、android.Rという最初からアンドロイドが用意してくれているクラスの設定を読み込むらしい。詳しくはEclipseでRという名前のclassファイルを読み込んでみると分かる。へぇーそーなのかー。
TextView id="@+id/text1"
このように指定すると、自分のアプリのRクラスから設定を読み込む。+をつけると設定がなければ自動的にRクラスを設定してくれる。
試してはいないが、おそらく+をつけないと自動的にRクラスを設定してくれないと思う。=見つからなくてエラー?になるのかな?

■チュートリアルにはバグがあります
無事チュートリアルで作ったアプリが動いたんですが、実はこのアプリにはバグがあります。
LogCatを開いたところ。ご覧のように、最後データベースをclose()していないためメモリが漏れてExceptionが発生しています。
(きちんとメモリ漏れを検知してExceptionを出してくれるdarvic VMは偉いと思う)

というわけできちんとデータベースをclose()してあげましょう。
Activityのライフサイクルは以下のようになっているので・・・
http://code.google.com/android/reference/android/app/Activity.html
Activity.onDestroy()をoverrideして、そこでデータベースをclose()すればよさそうですね。
@Override
public void onDestroy() {
  mDbHelper.close();
  super.onDestroy();
}
再度試したところエラーが消えました。ふう。

2008年10月12日日曜日

一通りレイアウト調整完了

  • ストレッチデザインになって横に長い日でも安心、IE7でも綺麗
  • タグクラウドはNew Blogger Tag Cloud / Label Cloud様からお借りしました
  • フォントが気に入らないのでそこは直すかも
  • 上に表示されるBloggerバーがいまいち
無事レイアウト調整が終わりましたので、今後はこちらをメインに使っていこうかと思います。
preタグをいちいち自分で入れなくてはいけないのが相変わらずですが、デザインがシンプルで横に長く、ソースコードを沢山入れることが出来そうです。行間がきちんと取られているのも読みやすくて素敵ですね。

欠点として、画像がPicasaサーバーに置かれるようになったのがちょっと迷惑です。あと上に表示されるバーを消したいです(ちょっと邪魔・・・)。

エディタはなかなか使いやすいです。下書きの自動保存が何より一番嬉しい。

テスト投稿

  • Bloggerの機能を試してみる
  • ソースコードはどれぐらい入れられるのか
  • クロスブラウザ対応は?
普通のテキスト 太字 斜体 文字色

左揃え
中央
右揃え
両端揃え・・・はうまくいかないな
  1. 番号リスト
  2. リスト
  3. リスト
引用
これがうまくいくとすごく助かる
if __name__ == '__main__':
sys.path = EXTRA_PATHS + sys.path
script_name = os.path.basename(__file__)
script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
script_path = os.path.join(SCRIPT_DIR, script_name)
execfile(script_path, globals())

画像を追加してみたい


ちょっと大きいかな
引用はうまくいかないのでpreタグを試してみる
if __name__ == '__main__':
sys.path = EXTRA_PATHS + sys.path
script_name = os.path.basename(__file__)
script_name = SCRIPT_EXCEPTIONS.get(script_name, script_name)
script_path = os.path.join(SCRIPT_DIR, script_name)
execfile(script_path, globals())

A-Liaison BLOG on Blogger

  • Bloggerに試験的にBlogを移設しました
  • レイアウト等はこれから修正します
  • タグクラウドが使えるようにします
Bloggerアカウントが取れましたので、試しにBloggerに記事をおいてみます。こちらの方が使い勝手がよいということになれば、完全に乗り換えることになると思います。

調べてみたところXML-RPCにも対応しており、Movable Typeから投稿が出来るみたいですね。
このMovable Typeとやらを使えば、iPhoneアプリから記事投稿が出来たりするんでしょうか。未調査。


以前のBlogはこちらから。
http://akisute.blog.shinobi.jp/