作者: 機械伯爵
日時: 2002/3/16(01:55)
P-3 君の名は?
   〜超強力辞書機能と名前空間〜

 Pythonは、ある意味では「新鮮味の無い言語」であると、生みの
親のGuidoさんも言っております。

 これは、前回説明したインデントブロック以外の特徴は、さまざ
まな言語からの借り物と言えるからです(まぁ、インデントブロッ
クもABC言語由来だけど)

 今回ご紹介する辞書機能は、もとをただせば SNOBOL4(後に、ICON
やAWKに引き継がれるわけですが) の連想配列からの借用ですし、オ
ブジェクト指向については言わずもがな(C++かSimula かな?・・・
Smalltalkではないと思う)。

 とはいえパクリも、Modula-3式超強力モジュール機能や、全てを
統合する「Python オブジェクト」という考え方を統合すると、いや
はやとんでもないバケモノへと変貌いたします*1

 Pythonでは、オブジェクトといえば通常はこの「Pythonオブジェ
クト」のことを指します(クラスインスタンスのことを指す場合も
たまにありますが、さすがに、C言語で言うところのメモリ領域を
もったモノを指すことはありません)

 最初の回で少し説明しましたが、Pythonオブジェクトには、リテ
ラルや数値変数に始まり、文字列・タプル(変更不可能なリストで
す)・リスト・辞書のようなコンテナ、ファイル、クラスインスタ
ンス(俗に言うオブジェクトですね)、関数・クラス・モジュール
といったものまで、全部含まれます。

 たとえば、import文で外部モジュールをインポートし、それをリ
ストに放り込んで使用する、なんて乱暴なことも、Pythonでは可能
です。

 Pythonオブジェクトは、すべからく一種の名前空間だとみなされ
ますので、名前が指し示すものが正確に置き換わるなら、変数やコ
ンテナに収納することができます*2

 そういえば、PythonにはC言語でおなじみのswitch-case文があり
ません。

 そのため、if文で一段づつテストする方法がチュートリアルには
紹介されていますが、処理内容を手続きにまとめてリストや辞書に
登録し、条件となる値をキーとして呼び出す方法のほうがスマート
じゃないかな、と思います*3

 特に辞書を使うと、キーに変更不可能オブジェクト(リストや辞
書以外なら、大体なんでも)が使えますので、処理の幅がぐんと広
がります(無論、アイテムには全てのオブジェクトが登録可能です)

 このように、たとえICONやAWK(やPerl?)で連想配列を使えると
いっても、よもやこのような使い方はできますまい(RubyやPerl6な
らできるのかしらん・・・)。

 まぁ、'x[y]()'なんて書き方に違和感を覚える方には、お勧めで
きませんけどね。

 さらに、Pythonには、クラスインスタンスのフィールドを「文字
列」によって呼び出す組み込みメソッド'X.__dict__[str]'がありま
すので、標準入力(ファイルやキー)から直接フィールドを操作す
るという離れ業もこなします。

 ついでに言えば、'__init__'メソッドに細工をすれば、メソッド
をフィールドとして登録可能なので、文字列を用いてメソッドを呼
び出すことさえ可能です。*4

 こういった変幻自在なアクセスは、カプセル化の精神を逆撫です
るような行為ではありますが、プロトタイピングとして考えたなら、
動作テストなどには威力を発揮するんじゃないかな、と思いますが
いかがでしょう?*5

 Pythonは、オブジェクト指向というよりも、名前空間のフル活用
を目指した言語であるのではないか、と思われるところがあります。

 モジュールやオブジェクトは、その一環として取り入れられたも
のであり、統一された名前空間利用のシステムにうまく組み込まれ
ています。

 Pythonオブジェクトは「名前」であり、超強力な名前空間システ
ムによって、できうる限りの柔軟性をもって利用されている、とい
うわけです。

 となると、Pythonオブジェクト指向とは、すなわち「名前指向」
なのかもしれませんね。



*1 とんでもないバケモノ
 Rubyの作者のまつもとさんが、「キッチンシンクアプローチの次
にくるのはオブジェクト指向だ」と言ってますが、「Pythonオブジ
ェクト指向」となると、整理整頓以外に「合体技」とでも言える独
特のアプローチが可能となるので、一種「キッチンシンクアプロー
チ×オブジェクト指向」といった感じになるのかもしれません。

*2一種の名前空間
 Smalltalk式に言えば、Pythonプログラムの文中で後ろに()の無い
名前は全てオブジェクトとして扱え、()がある場合はメッセージと
して扱われます。さらに、メッセージから()を除いてオブジェクト
として扱ったり、オブジェクトに()をつけてメッセージとして扱っ
たり(オブジェクトの関数呼び出し的用法)することができるため、
Pythonでは、書式によってオブジェクトなのか、メッセージなのか
明確にさせることが必要となり、メッセージの()が省けない、とい
うことになるわけです。

*3処理内容を手続きにまとめて
 Charls Moore(Forth言語の作者)のように、ループまで手続きにま
とめてしまうほうが美しいと感じるかどうかは、さすがに個人の好
みになると思われますが、少なくとも手続きにまとめると、いろい
ろなバリエーションが簡単に書けますし、ブロック化による再利用
もできますので、意外に応用範囲は広くなります。

*4 '__init__'メソッド
 コンストラクタに相当する組み込みメソッド。ただし、Pythonの
メソッド設定は独特で、第一引数をオブジェクト自身として、見か
け上外から追加するような操作を行う。このため、通常ではメソッ
ドはクラスのメンバーとしては認識されない(クラスは単なる名前
空間として使用されている)が、'__init__'メソッドの中でメソッ
ド名をフィールドとして代入することによって、メンバーとして登
録できる。ただし、気をつけないと循環参照になるため、特に必要
がなければ、この方法はお勧めできない(・・・なら書くなと? 
ごもっとも・・・)

*5カプセル化の精神
 カプセル化については、ライブラリやモジュールの設計者に対し
ての信頼があるかないかによって賛否両論があるのが事実だったり
します。実際、設計者が全ての状況を予測してインターフェイスを
用意するか、さもなくば運用についての可能性が狭められてしまう、
という矛盾があります。カプセル化を信奉している方は、人間をプ
ロメテウスの末裔だと信じておられるようですが、実はその出来の
悪い弟のエピメテウスの末裔なのですよ。だから、パンドラに苦労
する☆(プロメテウスは「先に考える者」、エピメテウスは「後か
ら考えるもの」の意味。エピメテウスの美人の奥さんであるパンド
ラが持ってきた「玉手箱」ならぬ「パンドラの箱」のお話は・・・
もうご存知ですね)