ラベル python の投稿を表示しています。 すべての投稿を表示
ラベル python の投稿を表示しています。 すべての投稿を表示

2013年12月22日日曜日

python __new__ と __init__ とコンストラクタ

appengineで__new__がどうたらこうたらというエラーに遭遇したので、今更調べてみました。
classの再定義(Typeオブジェクトの上書き)だけでもやっていけてしまいますしね。

端的に言うと、

__new__ は、オブジェクト生成直前に呼ばれる

__init__ は、オブジェクト生成後の初期化

ということらしい。

本来の「オブジェクト指向」「コンストラクタ」はメモリ確保そのものも含みますが、

http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming)

http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF

日本に蔓延している「オブジェクト指向っぽい何か」は
「Java系オブジェクト指向実装」を源流とするもので、
あの界隈では真のコンストラクトはコンパイラの仕事で、
「コンストラクタ」と呼ばれる機構には、初期化の役目しか残ってません。

故に、少なくとも日本語圏で、
__init__をコンストラクタと呼んでしまう風潮は間違ってはいないでしょう。

以前、「pythonにはnew演算子が無い」というエントリを書きましたが、
これはその延長線上(もしくはそれを遡った根っこ)にあるものですね。

pythonでは、クラス宣言=Typeオブジェクトの生成 であり、
本来の意味でのコンストラクタは、Type.__call__が隠蔽しています。
ということが多分、この辺りに書いてある?
https://github.com/python-git/python/blob/master/Objects/typeobject.c#720

__init__を呼んでるのは、実はobject.__new__の機能だったりするので、
__new__初心者はそこでハマるらしい。
http://stackoverflow.com/questions/9367126/why-is-init-not-called-after-new-sometimes

問題の__new__ですが、慣れるより見習え!、ということで、色々ソースを捜索しました。
google_appengine_SDKはpython達人実装の宝庫です。

http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/db/djangoforms.py#714

基底クラスの「亜種」を動的に作るのに使ってる場合が多いみたいですね。

とはいえ、python2.4以前では、似たような機構を__metaclass__でやってたらしい。

http://docs.python.jp/2.4/ref/metaclasses.html

python-SDKでもそっちの方の印象が強いです。Modelクラスの小細工に使っていたような。

http://code.google.com/p/googleappengine/source/browse/trunk/python/google/appengine/ext/db/__init__.py#798

意味は未だに判らない。__new__の方が機構的に「初心者向け」でしょうか。

PHPとかだとevalで強引に出来なくもありませんが、C#/Java族だと逆立ちしても無理ですね。

2013年1月20日日曜日

優れた Python プログラマを見分ける10+1の質問。らしい。

http://methane.hatenablog.jp/entry/20110301/1298972457

やっべ、ほとんどわかんね。

list, tuple, dict, deque, heapq, bisect がどういう場面に適しているか説明しなさい

やっべ、使ったことねえ。アンチョコ(要するにマニュアル)見ていいのかな??
  • list 不定長の単純配列。非ソートデータの保持
  • tuple 一時的な小さいデータの保持。不変。
  • dict 連想配列。色々。
  • deque ※使ったことねえです
  • heapq ※使ったことねえです
  • bisect ※使ったことねえです
全体的には、「pythonでミッションクリティカルな案件の経験があるか?」的な感じですね。小生、もちろんpythonで仕事をしたことはありますが、そんなシビアな案件じゃなかったので、プロファイラとか使わないで済んでます。料金が変わるまでは、appengineの無料quotaで済んでたしね。

現在の出稼ぎでは、残念なことにPHPです。PHPでプロファイラ使う話はあまりないですね。と言うか、実行時間の殆どはphp-activerecordと、adobe amf framework だったりするので、チューニングで頑張る余地はあまりないです。これらのフレームワークのロード時点で、メモリ3MBづつ使うので、memory_limitは、8MBから増やさざるを得ません。

2012年9月30日日曜日

appengine python27 threadsafe:true

先日、python2.7環境で「動かしただけ」のappengine アプリケーションを、本格的に threadsafe:trueを試してみました。

例によって、情報は足りてるのですが、英語のドキュメントを読んでも今ひとつ要領を得ません。

早い話がこうです。

  • threadsafe:trueにしたら
    • app.yamlは
      • actionsの拡張子はすべて"app"にしなければならない
      • いや?*.pycじゃね?と思うかも知れませんが、カンケーないらし。
    • 個々の*.pyは
      • import webapp2
      • webapp2.WSGIApplicationの変数名を、必ず"app"にしなければならない
        • yamlの*.appってそういう意味????
      • 直接、深いディレクトリの*.pyを起動することは出来ない。
        • ひょっとして、modulename.modulename.app とか書けばいいのか??

2012年9月20日木曜日

HTMLエスケープ in Python2

HTMLエスケープをせざるを得なくなりました。

urllib.unquoteで出来るよって?違うそれは「URLエンコード」別件です。紛らわしいよHTML業界。

  • HTMLエスケープは、特殊文字とHTMLタグを避けるための小細工
  • URLエンコードは、特殊文字を、HTTP GETクエリストリングを避けるための小細工
小生が今知りたいのは前者です。なぜなら後者は有名だから。
結論から言うと、次のうち幾つか。らしい。


別パッケージを入れなきゃならんのは色々アレなので、

  • from xml.sax.saxutils import escape,unescape

辺りで行ってみようかと

2011年10月22日土曜日

そーいや、WEBの世界には「セッション」が有ったなあ

他の記事を書いた後、他の人ってどうなんだろうと検索してみたら、

http://d.hatena.ne.jp/kwatch/20100613/1276385931
PHPは唯一、セッション管理を内蔵してる(意訳)

という主張がありました。言われてみればその通り。

pythonについては、先日pythonカンファレンスに出てみましたが、「フツーwsgi」らしいです。cgiの話なんか誰もしません。そういう状況ではPHP/Perlにしちゃうのでしょうか。cgi.pyの存在は知らない人の方が多いかもしれませんね。って言うか筆者はpythonでCGIを作る気がないので存じませんでした。

この記事を最後まで書いちゃってから気づいたのですが

  • PHPはmod_php
  • しかしpythonはcgi.py
  • しかしrubyはcgi.rb
それぞれ前提条件が違うので、比較にならないですね。
比較するなら、
  • PHPはmod_phpを
  • pythonはmod_pythonを
  • rubyはmod_rubyを
が筋でしょう。

筆者はperl5で、クッキー&セッションを自作して、酷い目にあったクチなんで、PHPの$_SESSIONには感涙したものです。しかも、クッキーが使えなかったら、表示する筈のHTMLタグに介入して、PHPSESSID=とかパラメタを勝手に付加する。というのも画期的ですね。これで助かってるガラパゴスケータイゲーム業者も多いはず。

筆者は、公私共に、appengineで色々運用していますが、セッションが無くて困ったことがありません。何でだろな、と思ったら、ユーザ認証ベースで作ってるからですね。そういう案件だから、ってのはその通り。

セッションが必要な典型的なケースは、ショッピングバスケットでしょうか。ユーザ認証があれば大丈夫ですよ。って言おうとしたら、未登録の人が未登録のまま買い物をするケースが結構ありますね。買い物客としては筆者もよくやります。そういう時にはセッションは有った方が良い。

appengine/wsgiのお作法では、セッションはデコレータとして実装して、後付けした方が美しい気がします。それが出来るのがpythonの利点ですし。

うまく行ってるか判りませんが、まさしくデコレータで自作した人は居るらしい。
https://sites.google.com/site/yomusu/googleappengine/oresession
http://d.hatena.ne.jp/coiledcoil/20110212/1297491800

mod_pythonにはセッション機能があるようですね。
http://www.python.jp/doc/contrib/modpython/pyapi-sess.html

djangoもセッション機能を内蔵してるらしい。
http://www.djangobook.com/en/2.0/chapter12/
ただしdjangoは、mod_python/wsgiの2択らしいんで、cgi.pyは使ってませんね。

総論としては、pythonでcgi.pyを使ってる人は変態。

2010年9月12日日曜日

PHP5.3の名前空間がイケてない

名前空間の実装は、コンパイラ実装者にとっては悩みの種でしょう。
そういう事にしてください。

散々悩んで、PHP5.3みたいな有様になってしまうケースもままあります。

pythonの厳密には「モジュール」があり、その内側で「名前空間」に近い概念が使えますが、
非常に洗練していて、矛盾がありません。
その根幹は、名前空間ですら「オブジェクト」であるからです。
具体的には、module型。らしい。

  • Pythonのmodule型では
    • 1ファイル中で、名前空間(的なもの)を切り替えることは出来ない。
    • 変数や関数群は、単に実行中のmoduleのプロパティの一つに過ぎない。
    • importは、module型オブジェクトを、同名の変数に取り込む。
    • クラス定義(オブジェクト)とインスタンスは、収録している変数が違う筈なので、混同のしようがない。

javascriptも、これに近い運用ができますね。
端的に言えば、「別の名前をつける筈」なので、「「名前空間名と、クラス静的メソッド等を混同する」ような作り方はしない」

故に、これが、「名前空間専用の、階層区切り文字の設置」の理由にはなりません。
こんな理由が、バックスラッシュの理由で、まかり通っちゃ如何でしょう。
PHP関係者が、如何に他の言語畑とくらべて緩いのか。
言語側から、これを強制できなかったのは、PHP5.3の大失敗の一つでしょう。

2010年8月27日金曜日

youtube-dl 日本語版

職業プログラマで、自宅あるいは会社のPCに、
linux入れてます、って変人は少なくないと思います。
いやそういう事にしてください。

linuxであれば、youtubeの動画の保存には、
当然youtube-dlを使ってますよね。
いやそういう事にしてください。
http://bitbucket.org/rg3/youtube-dl/wiki/Home

コマンドラインのダウンローダは数あれど、
ファイル名に、youtubeの動画idを付けてくれるのは意外と少ないです。
#動画のページタイトルからタイトルを作ってくれるのは当たり前。
デフォルトで、というべきか?

ところが、残念なことに、日本語のファイル名を作ってくれません。
日本語部分というか、黄色人種の国の文字がバッサリ落ちます。
まあ作者は英語圏の人っぽいので、まあ読めない文字でファイル作られても楽しくはないでしょう。

仕方がないので、個人的に日本語パッチ当てて使ってましたが、
bitbucketでは、他人のフンドシで相撲がとれる(fork)らしい。

それって。本家の人はどう思うんだろう?
そしたら居るわ居るわ派生バージョン。
http://bitbucket.org/rg3/youtube-dl/descendants

はい、forkさせていただきました。
https://bitbucket.org/kamawanu/youtube-dl-japanesefilename
mercurialだっつーのも活けてますね。
#gist/githubはあっちはあっちで使ってますが、gitには微妙に馴染めません。

と思っていたら、githubに引っ越しちゃってました。

やっぱりforkするわけですが

2010年5月21日金曜日

python elixir、しばらく使い込んでみました

python elixir。その後、しばらく仕事で使い込んでみました。
http://elixir.ematia.de/trac/

基本的に import * を推奨しちゃってる感じですね。
設計方針的に。

勝手に?暗黙に?処理する部分が結構あって、
エラーの出方に意表を突かれます。
それが馴染むか否かですね。

setup_all() とか、
現在の名前空間から、Entityの継承クラスを探して、
それぞれ「重要な何か」を仕込んでいるらしい。

リレーションしてる様なケースでは、普通はjoinするのが筋なんでしょうけど
#ついapp engineのつもりで、
他のEntityのqueryを作るようなメソッドを書いちゃったんですが、
いざ使おうとしたら、queryが居ません。みたいな。

発想は美しいような?妙にチグハグなような?
じゃあmetadata.bindは何をやってるんだ?的な憤りはままありますが。

elixirを使う場合は、Entityの実装はあまり小分けにしないで、
__all__をちゃんと書いた方が上手く回る。ということなんでしょう。
#アレ?それってpythonでは常識??

筆者は、名前空間を上書きしない主義。だったので、
抵抗というよりは、カルチャーショックでしょうか。

総評としては、elixir(引いてはsqlalchemyも?)は、
pythonマスターによる、pythonマスターの為の。
という感じでしょうか。

2010年5月12日水曜日

python elixir

appengineのdatastore実装が素敵過ぎて、他の案件でも使いたいのですが、
「顧客の要望」で「CGI環境」と言われちゃう事がままあり
そういうケースでは、djangoごと引っ張ってくるのは無理っぽい。

と思ってる人は多いはず。

筆者が試したのはelixirです。
http://elixir.ematia.de/trac/wiki

当時は0.6.0ぐらいだったと思います。

結論から言うと、悪くはないのですが、
sqlalchemyのwrapper的な生い立ちのせいか
微妙なところで変なアクが有りますね。


  • ModelというかEntityは、概ねdb.Modelの様な調子で書けます。
    • Field()への入れ子(?)宣言なのが何とも言えない。
  • 外部キー制約は、OneToMany(), OneToOne()で行けます。
    • 内部で、ReferenceProperty的挙動もやってくれます。
  • 定義したとおりのプロパティ名で、キーのリンク先データを引っ張ってくれます。
  • SQLに逐一送っちゃわずに、内部でトランザクションエミュレーションしてる模様。
  • setup_all()をやらないと、commit()でもデータを書き出してくれなかったとか。
  • 故に、データの書き出しは、Entityのsave()じゃなくて、session.commit()だったりとか。
    • # Entity.put = staticmethod(session.commit) #とかやっておくべきか?
  • setup_all()で、Entity.queryが沸いて出るとか。
  • Entityのquery.filer_by()関数で、新しいオブジェクトを返すので、それを変数に入れ忘れると、全件検索になっちゃうとか。
  • 複数カラムにまたがるインデックスを貼りたい場合は、sqlalchemyのクラスを引っ張ってくる必要が有っちゃったりとか。


その一方、実装は、pythonの限界に挑戦しちゃってる感があるので、参考になります。

pythonのテンプレートエンジンmako

最近は、pythonアリの発注(受注)が出てきて嬉しい限りです。

google appengineフレームワークには、
テンプレートエンジンが同梱しており、
これがなかなかの使い勝手。

サーバも含めてオマカセ案件では、
appengineにしちゃうのが最近の筆者の手口です。

非appengineのプロジェクトでも使いたいものですが、
納品先の事情でCGIベースでしか実装するしかない場合は、
他の選択肢を探さざるを得ません。

仕方なく、テンプレートエンジンを探す訳ですが、
色々比較してみて、結局 mako とやらで実装中です。

Mako Template of Python
http://www.makotemplates.org/

生pythonコードを埋め込めるタイプ。
構文もpythonそのものに酷似しています。
内部的にpython(しかもclassに)に変換しちゃってるらしい。

故に、他のテンプレートファイルを「継承」できるらしい。

例えば、ページのフッター&ヘッダーを差し込みたい場合。
それぞれ別ファイルを作って、includeするのが一般的だと思いますが。

ページ全体をヘッダー&フッター付きでデザインしておいて、
個々のページは内側だけ作って、inheritすれば済みます。しかも1回で。

記述のテイストがPHPに似ているので、
「テンプレートエンジン」として「ラクになってる感」は薄めですが、
継承はなかなか使いでがあります。


ライブラリの構成ファイル群は、
少ない部類に入るような気がします。
スピンアップが早そう。って事ね。
app engineで強引に使ってみるのもアリかもしれません。

2010年5月6日木曜日

app engine SDK では110過ぎの人の誕生日が扱えない?

app engineが、という、pythonのlinux版は、
datetime型は、1900より過去をサポートしません。

1899年生まれの人の誕生日を、strftimeとかすると、ValueErrorを喰らいます。

また悩ましいのが、strftimeの制限なので、
datetime自体は、1899以前を入れようがコンストラクト出来るのです。

例えば、datastoreに誕生日が入っていて、

SDKの _ah/admin/datastore でdatastoreを眺めようとすると落ちます。
うーん。

検索してて気づいたのですが、1900年って、昔懐かしい2000年問題の一部ですね。
http://ja.wikipedia.org/wiki/2038%E5%B9%B4%E5%95%8F%E9%A1%8C

strftimeの動作は、プラットフォーム依存らしいので、
http://www.python.jp/doc/2.5/lib/strftime-behavior.html#strftime-behavior
SDK的はどうにもならない模様。
と言うか、appspot.comでは、逆に1899年以前でも通ります。
本当に実装依存っぽい。

strftimeの内部で、これくらいやっちゃって欲しい。とも思う。

仕方ないので、パッチを当てるしかなさそう。


ネタが細かすぎて、パッチファイルを無くしそうなので、gistに貼りました。


2010年5月2日日曜日

pythonのselfとimportの関係

別エントリでも書いた通り、pythonは、クラスメソッド宣言の中で引数にselfが必要です。

まず前提条件として、プログラム言語には、「暗黙主義」と、「宣言主義」があると思います。いずれも筆者の解釈。

「暗黙主義」の代表は、PHPでしょう。

例えば、PHPは、クオートしてない大文字の単語を、勝手に文字列定数として使用します。変数のドルを忘れてたとしたら?バグります。しかも、連想配列のキーが未定義でも、シレっとnullが戻ります。

もしくは、折角define()したのに、タイプミスしちゃって、似た文字列をキーに使っちゃったりとか。

PHPでは、クラスメソッド内部では、$thisが暗黙で使えます。自動定義と言うべきかも知れません。しかも、クラスの壁を越えられます。クラスメソッド内部から、別クラスの別メソッドを、静的メソッド的に呼び出せます。しかも$thisがそのまま伝わります。

例えば

class one { function one(){ var_dump($this); } }
class two { function two(){ one::one(); } }
$aaa = new two;
$aaa->two();


継承してませんよ。

もう変数のスコープもヘッタクリもありません。

良いか、悪いか、と言ったら、悪い。と言えましょう。

pythonは、完全に「宣言主義」です。

前述のselfは、webを眺めてみると賛否両論。C/Java育ちの人には評判が特に悪いような。しかし別エントリでも書いた通り、クラスメソッドの呼び出し方が何通りも或るので、関数宣言段階でそれを明示することは有効です。

例えば、Javaだったら、静的メソッド呼び出しを使うにはstatic宣言が必要です。pythonのselfは、その逆宣言だと思えば良いでしょう。

デコレータの鑑みるに、どうやらクラスメソッドは通常関数のwrapper的に作用しているようなので、構造上selfが必要だったのかも知れませんが、筆者は結果オーライだと思っています。

「宣言主義」は、importにも現れています。

ディレクトリ名がパッケージ名になっちゃうのも賛否両論ですが、asで別名を振れるので、特に困ることはないはず。

importも含めて、関数もクラス宣言も、オブジェクトとして変数の中に入っちゃってるので、再定義が出来てしまう、という諸刃な側面もあります。

標準状態では、ほとんど何も出来ないのでimportを沢山書きます。ブログなんかで、面倒なのだろうけど、

from ナントカ import *

をやっちゃってる人は多いですが、意図しない置き換えが、発生する可能性があります。

要するに、

  • オレのモジュールの一部が、
  • ナントカの中身で書き換わる可能性がある。


面倒なのは判るけど、モジュール階層から呼び出すべきでしょう。

selfもimportも面倒だろうけど、伊達や酔狂で、ああなってる訳ではないよ。筆者の言いたいのはそういうことです。

2010年4月23日金曜日

pythonにはnew演算子がない

pythonでは、インスタンスの作成で、new演算子を使いません。
というか、「new演算子」という構文が存在しません。

PHPやJavaやらCやらの経験者からすると、
これはやや気持ち悪い。
具体的には小生がそうでした。

ただし、その方法論が腑に落ちると、「new「演算子」」のある言語が「オブジェクト指向言語」に見えなくなってきます。少なくとも小生はそうです。

順番に行きましょう

pythonでは、普通の言語でいうところの「クラス宣言」は有りません。
しかし、同等の機構はあります。クラスオブジェクトの作成です。

http://www.python.jp/doc/2.4/tut/node11.html#SECTION0011320000000000000000

下記の例で言うと、anyclass変数に、クラスオジェクトが入ります。
 class anyclass(object):  pass
インスタンスの作成はどうするかというと、作って有るはずの、クラスオブジェクトをcallしてるわけです。だからnew演算子を付けちゃいけません。「呼んでる」だけだから。
instance_object = anyclass()
これはpython的には、「class宣言は、type型インスタンスを作ってるだけで、それはcallableである」というところです。フツーの言語が、new演算子を起点にして、「コンパイル時」にやってることを、callableを経由して「実行時」にやってる。ここがpythonの肝です。

もちろんこんな空っぽのクラスは何の役にもたちません。とりあえずメソッドを足します。
class hasmethod(object):
 def method1(self): pass

pythonは、言語としては珍しく、メソッドの引数として「自分インスタンスオブジェクト」を第1引数に書かなければなりません。

インスタンスを作ると、クラスメソッドとインスタンスオブジェクトが結びつきます。
instance1 = hasmethod()
instance1.method1()

ここでのポイントは、

instance1.method1() と、hasmethod.method1() は別物である。

ということです。

  • 前者は、インスタンスに結びついたメソッドオブジェクト
  • 後者は、結び付いてないクラスメソッドオブジェクト。
後者は、「結びついてない」ので、
インスタンスオブジェクトをどうにかして渡す必要があります。

それで第1引数 self の出番というわけです。

前者は、「結びついてる」ので、pythonがselfを勝手に足してくれます。故に、インスタンス関数呼び出しでは、self 以外の引数だけを書くわけです。


instance1 == self
とは言え、この調子だと、普通の言語で言うところの、静的メソッドは?このままでは無理です。しかし方法は有ります。

class statichas(object):
 @staticmethod
 def method1(): pass

@staticmethodデコレータを挟むだけです。

フツーの関数宣言は、selfが必要ですが、今度は逆に、selfを入れると怒られます。pythonは、selfを引数に勝手に加えるのを辞めます。staticmethodは、そういうマーキングをやってるらしい。この状態では、method1を直接呼び出すことができます。 http://docs.python.org/c-api/structures.html#METH_STATIC

statichas.method1()

ただしこれでは問題が無くもありません。関数の中からは、クラスもインスタンスも解らないので、クラス内の他のメソッドも使えません。

#逆に、一人完結してます。というアピールに#@staticmethodを使うのは、筆者はアリだと思います。

前述のクラスメソッド表記で呼び出せなくもありませんが、クラスを継承する状況を想定すると、固定で書くのは避けたいですね。

ハイ。そこで出てくるのは、@classmethodデコレータです。フツーの言語の、静的メソッドに相当するのは、むしろコッチでしょう。
class statichas(object):
 @classmethod
 def method1(cls1):pass
引数に必ず1個入ります。わざわざclassmethodと付けたのは意味がもちろんあって、
「「インスタンスオブジェクト」で無いモノ」を付けてね」という意味です。らしい。http://docs.python.org/c-api/structures.html#METH_CLASS 前述のtype型インスタンスなので、歴史的&一般的にselfとは付けません。世間一般にはclsとだけ付けるっぽいですが、小生は3文字変数に辛い思い出があるので、"cls1"にしてます。
statichas.method1()
表面上は、さっきのstaticmethodと同じ使い心地です。しかし、cls1には、statichasクラスオブジェクトが入ってます。classmethod同士を呼び出す分にはこれで行けますね。

statichas == cls1

しかも継承すれば、継承後のクラスオブジェクトがcls1に入っている。

という寸法です。

面白い発想ですね。

具体的には、app engine python-SDKのgoogle.appengine.ext.db.Model.get がlassmethodです。小生は、この辺りの実装を眺めていて、感動すら覚えました。

class「定義」の構文は、フツーの関数定義を「メソッド呼び出しに変換する」処理であると考えれば、腑に落ちると思います。故に、$thisを暗黙で「渡さない」方が何かと都合が良いわけです。

これを利用して、定義済みクラスじゃなくてtypeオブジェクトに、メソッドを後付けできます。「class定義」がコンパイラの仕事じゃないから出きることですね。真の動的言語の何たるかを見た気がします。

そんな訳ですので、フツーのインスタンスメソッドから、classmethodを使うときにはどうするか?構文を区別する必要があります。
self.__class__.method1()
static::method1とか書くより解りやすい気がすると思うのですが、どうでしょう。ダブルコロンとかバックスラッシュとか要らないわけです。オブジェクトだから。

今まで、インスタンス作成、メソッド呼び出し、と色々述べましたが、

表記上の違いはほとんどありませんし、Python内部でのメカニズムの違いも殆どありません。 他の言語でいうところの「クラス定義」は、「タイプ型オブジェクト」でしかないので、「◯◯オブジェクトのメンバ関数を呼ぶ」という機構は統一できてるわけです。


  • インスタンスメソッドを呼び出す場合
    • instace1インスタンスオブジェクトのmethod1メンバをcallする。
    • 特にmethod1にマークは付いてないので、引数の先頭にinstance1を挿入する
  • staticmethodを呼び出す場合
    • class1タイプオブジェクトのmethod1メンバをcallする。
    • staticmethodマークが付いてるので、引数には何も足さない。
  • classmethodを呼び出す場合
    • class1タイプオブジェクトのmethod1メンバをcallする
    • classmethodマークが付いているので、引数の先頭にclass1を挿入する。



呼び出し可能なオブジェクト(特にcallableと呼ぶ)を、呼んでる(call)だけ。

これに付きます。


これが腑に落ちると、途端に「new演算子のあるオブジェクト指向言語」が駄目言語に見えます。

筆者はここまで徹底したオブジェクト指向を他に知りません。
#ご存知の方は、教えてくれなくてもいいです。長くなりそうなんで。

識者が言うところによると、pythonは、広義には関数型言語らしい。
haskelには気絶しそうになりましたが、大分判りやすくて助かります。

2010年4月10日土曜日

appengineの真骨頂は、pythonにあり

日本の、エンタープライズ界隈の方々は強情で、
app engineのdatastoreを難解だと感じている様です。+

JavaのJVMによる、他言語実装、例えばrubyもあり、
http://jruby.org/
app engineでrubyを使う人も居るには居るらしい。
http://code.google.com/p/appengine-jruby/

RDBのJava実装がありまして、
OpenOfficeのBaseでも内蔵してる代物なんですが、
http://hsqldb.org/

これをdatastoreのミドルウエアとして使った人も居ます。
http://www.littlesoft.jp/sql4g/

確かに、RDBMを使えれば、リレーション使いまくりですが、
そもそもJavaは、「固い」言語なので、datastoreの柔軟さが活かせません。

って言うか、そこまでpython使いたくないですか?と聞きたい。

pythonのwsgirefとか、webappは、JavaのServletに近い考え方ですね。
どっちが先だか私は知りません。
しかし、app engineの真骨頂はdatastoreにあります。

RDBに、GUIツールが存在するのは、「管理が面倒臭い」の裏返しです。
Java自身のためのEclipseが存在するのと同義です。

しかし、datastoreのORマッピングなら、ソースを修正するだけです。
pythonなら多重継承すらできます。

いやもう、SQLなんか書いてられませんよ。面倒で。

JavaのJDOとやらからでも、比較的簡潔な記述が書けますが、
http://code.google.com/intl/ja/appengine/docs/java/datastore/dataclasses.html

pythonのそれとは簡潔さが比較になりません。
http://code.google.com/intl/ja/appengine/docs/python/datastore/entitiesandmodels.html

記述量は、5倍以上ですね。
筆者は(python版の切り口に対して)「え?これだけでいいの?」と素直に感動しました。

pythonのアレを強引にJavaで例えるなら、
classのstatic変数の初期化で、カラム名&型の定義をしています。
しかもnewすると、同名の変数が、データカラムとして使えるという。
Javaでそんな記述は不可能です。pythonだからこそ可能です。

しかしこれはpython djangoのORマッピング機能上に実装したものらしいので、
http://docs.djangoproject.com/en/dev/ref/models/instances/
python djangoが、もともとイカしていたといった方が良いでしょう。

datastoreが難解なわけじゃなくて、
JDOのアノーテーションが気持ち悪いのです。
見比べでつくづく思いました。

2010年4月5日月曜日

python gdata のtext_db は、大文字カラム名が使えない

python gdataの、
text_dbは便利なのですが、
いざ、AddRecordしようとすると、大文字キーのデータを省いてしまう。らしい。
#判らなくて泣きそうになりました。

CreateTableで、大文字カラムは作れるので、
まるで無視してるわけではないらしい。のですが。
それが逆に、事態を混乱させてるという。googleサービスにありがち。

あっちこっちソースを追いかけて、結局判らなかったんですが、
atomプロトコル上で、フィールド名にまんまカラム名を使ってるのを発見。
漢字カラム名も通ってる模様。

もしかして?と思って、string.lower()したら通りました。

これで悩んでいるの、筆者だけ?と思って、検索してみたら、
大抵のサンプル実装は、小文字ONLYなので、気づいてない人も結構居るかもですね。

アンダーバーもダメらしい。

pythonでは「大文字変数には特別な意味がある」事になってるらしいので、
無視するのはフツーのことかも知れません。

とりあえず、小文字変換することにしました。

2010年4月3日土曜日

pythonは、標準関数を置き換え放題

全くの不可抗力で発見しましたが。

pythonって、"str"を変数として使っても怒られません。
str = ""
通常、「ビルトイン関数str」として使っているモノは、
実は、変数strの中身がcallableだった、というだけなのです。

知る人ぞ知る、かも知れませんが、わざわざこんな事をやる馬鹿は居ません。しかし、筆者はまだpython歴1年なので、勘弁してください。

こうすると復活します。
import __builtin__
str = __buitin__.str

言語のセキュリティとしては、かなり緩いですね。「変数を書き換え」を制限する方法が存在しないので、第3者のモジュールを持ってきて、無改造でもかなり色々出来ます。

例えば、appengineのdjango.utils.simplejsonは、datetimeを受け付けません。not serializableとか言って、例外で落ちます。

しかし、その例外を出してる関数は、呼ばれていきなりraiseしています。オーバーライドしてね。と言わんばかりです。これを外側から書き換えてやれば、datetimeを変換できるようになります。

gistに貼っておきました。
http://gist.github.com/358287

pythonで商用ソフトを作ろうか、と思うと、この辺りで躊躇しますね。メソッド名も全部__dict__で見えちゃいますし。最終的には、難読化しなきゃならんのかと。javascriptがそうである様に。

しかし、デコレータは、この機構を最大限活用しての事なので、pythonでは必要悪と言えるかもしれません。

2010年4月1日木曜日

pythonのデコレータは

pythonのデコレータは、なかなか面白い発想ですね。

pythonでは、
関数宣言は、「callableオブジェクトの作成」でしかない、ので、
関数宣言自体を、他の関数の引数に渡せる、と言うことであって、
それだけでも、wrapper関数を、サラリと書ける。
と言うことなのだろう。と思う。

python2.3以前でも、
staticmethod「ビルトイン関数」を通して、
同じ変数(メソッド名)に入れ直す、みたいな構文はあったのですが、

python2.5からのデコレータ構文を、
class文の中で使って、デコレータ関数からcallableオブジェクトを返すと、
どうやらそれを新しい関数宣言として使ってくれる。らしい。

まあ2.5自体、2年以上前のリリースなので、時期的には今更ですが、
筆者個人は、python歴1年生なので、筆者としては衝撃です。

オブジェクト指向の軽量言語ならではの発想です。
軽量言語であっても、関数類の再定義を認めてないものが殆どです。

C++/Cまで遡れば、構造体の関数ポインタを入れ直す感じに似てますね。

関数をサラリと再定義できるのさることながら、
1行書き足すだけで使える、のが素晴らしい。

とりあえず思いついたのは、appengineのRequestHandler。
SDKでテストしているうちは何とも無かったのだけど、
appengineに突っ込んでみたら、Quota系例外がボコボコ出るので、
基本、try/exceptは遣っておいた方が良い。
のですが、デバッグ中は逆に面倒だったりします。

そこでデコレータの出番です。
作ってみた。gistにあり升

http://gist.github.com/351412