Diary?

2009-07-15
Wed

(09:54)

打ち合わせで俺の書いたコードを読んだ檜山さんから「__init__.py にいろいろコードが書かれてるのと空っぽの場合とがあるけど、あれ何?」という質問を受けたので、 Python におけるパッケージとかモジュールの設計の指針についてちょっと書く。

まず最初に言葉の定義。 Python におけるモジュール及びパッケージというのは、オフィシャルの下記の文書に書かれている通りである

ざっくりと抜き出すと

モジュール
.py ファイル一個か C による拡張(今回は関係ない)かパッケージ。つまり再利用可能単位の総称
パッケージ
多くの場合において __init__.py と他の .py ファイルを含んだディレクトリ

となる。これらの仕様の大元の文書は次の奴だな。

なので基本的な Python におけるモジュールとパッケージの使い分けは

  • ファイル一個で済ませられるならモジュールとして作る
  • でかくなりそうならパッケージにする。 __init__.py の使い方は割と自由だが、何かしらの方針を持った方がいい
    • __all__ 変数と必要であればパッケージ内のモジュールからの import
    • パッケージの初期化コード
    • 各モジュールのクラス/関数を元にした上位 API
    • あるいはパッケージ内のモジュールを拡張/応用機能として、基本的な機能を __init__.py に書いてしまう
    • 特にコードを書く必要がないならパッケージの pydoc だけは書いておく

となりそうなものだ。ちなみに Python の標準ライブラリを見てみると、 2.5 の時点でパッケージになっているのはあまりない。そんな中でパッケージになってるモジュールの __init__.py をいくつか見ていくと、

wsgiref
pydoc のみ
email
モジュール初期化コードと上位 API というか便利関数
logging
Handler クラスを始め、基本的なクラスが定義され、パッケージ内の各モジュールでそれらのクラスを使っている
ctypes
モジュール初期化コード

とまあ、割といろいろな書き方がされているので、一通り読んでみるといいかもしれない。

(18:33)

以下、エキスパート C プログラミングより引用。ちょっと極端過ぎる例だけど、言語独自の慣習・標準などを無視することの一つの到達点がこれだ。

「CはAlgolではない」

1970年台の後半、ベル研でUNIX Version 7用のシェルを開発する際に、Steve Bourneはプリプロセッサの機能を使って、CをAlgol-68風に使おうとした。

(中略)

#define STRING char *
#define IF if(
#define THEN ){
#define ELSE }else{
#define FI ;}
#define WHILE while {
#define DO ){
#define OD ;}
#define INT int
#define BEGIN {
#define END }

これらを使うと、プログラムはこんな風に書けるようになる。

INT compare(s1, s2)
    STRING s1;
    STRING s2;
BEGIN
    WHILE *s1++ == *s2
    DO IF *s2++ == 0
        THEN return(0);
       FI
    OD
    return(*--s1 - *s2);
END

(中略)

このAlgol風C言語Bourne方言は、International Obfuscated C Code Competition−−作成したプログラムの読みにくさと複雑さを競う異様なコンテスト−−を誕生させるきっかけになった。

この Bourne シェルの開発エピソードから読み取れる教訓は、自分にとって自然な記法が他人にとっても自然とは言いきれないということだ。例えば俺は Python の組み込み型が小文字で始まっていることがそこまで不自然だなんて思ってない。仮に組み込み型の名前が大文字で始まっていた方がいいと思う人が大多数を占めたとして、組み込み型の名前を変えたり __builtin__ を直接いじるような変更をおいそれとやるのはどうかと思う。

あと件の記事の発端は「ローカル変数に心置きなく str などを使いたい」というものだが、そもそも str だの dict だのは変数名としてはまったくもって無意味で、本当に何かしら意味のある名前を付けなければならない場合には使えない。そして別に意味のある名前である必要性がない場合(lambda s: s.strip().lower() なんてλ式の仮引数名を誰が気にするんだ?)は一文字変数で別にいいだろう。

何にせよ、組み込み型にエイリアスを付ける事にそこまでの意義は感じられない。ただローカル関数に str などと付けられるというだけのメリットが、そのコードを読んだ第三者に「この Str とは何だ?」と余計な事を考えさせ、時に混乱させ、場合によってはポータビリティの問題を抱えるかもしれないというデメリット(__builtin__ を変更してる事に依存したコードを、それと気づかず別の環境で動かそうとして、 __builtin__ を変更するコードが入ってなかったらどうなるかな?)に本当に見合っていると思っているなら別に止めはしない。そのコードが International Obfuscated Python Code Competition の起源にならないことを祈るよ。

(19:15)

今日の昼飯及び晩飯はほぼ完全に我流の多分だけど回鍋肉と思われるもの。今回は微かな記憶と勘のみで作ったんだけど、その割には上手く行った。

使った食材は

  • 玉ねぎ1個
  • ピーマン2個
  • パプリカ1個
  • 豚バラ230gぐらい

で、調味料はこんな具合……だったはず。

  • 醤油大さじ2杯弱
  • 豆板醤小さじ1杯
  • 鶏ガラスープのもと小さじ1杯弱
  • みりん小さじ1杯
  • 水大さじ2杯

というかだな、そもそも事の発端はちょっと余り気味のピーマン & 玉ねぎとネタで買ったパプリカをどうするかだったのだ。それで何となく「これと豚バラを豆板醤で炒めたら回鍋肉じゃね?」と思ったので、残りの具材を買ってきて、「どうせ炒めて調味料入れるだけだろ」と完全になめた態度で料理開始。

豚バラを適当な大きさに切って塩コショウをまぶしたら

炒める。しっかり炒める。親の仇のように炒める。そしたら野菜を突っ込んで炒めて、その後調味料を入れる。この辺のプロセスの写真はデジカメの電池切れにより撮れなかった。ってか予備のバッテリーぐらい用意しとけという話か。

でまあこれは当然昼間にできたてを撮影したものではなく、さっき電子レンジで温め直した奴なんだが。冒頭に書いた通り、適当に作った割には結構美味しかったな。ちなみに今回は3食分ほど一気に作ったので(2食分にするつもりが目測を見誤った)、明日の昼ご飯もこれ。

Creative Commons
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。