Classes

一番の難所 (?) であるクラスに関して勉強します。なぜ難所?かというと単にこの章が長いからです (笑) 。ちょっとずつでも毎日こなして行こう。


まずはPythonにおけるクラスの特徴がC++Smalltalk、Module-3と対比して書かれています・・・が私、Module-3についてまったく知りません。なのでModula-3との対比はいまいちピンと来ませんでしたが、特徴的だと思うところを挙げてみます。

  • 多重継承あり
  • クラス定義を動的に変更可能
  • 全てのメンバーは基本Public (データも!)
  • 基本データ型からも継承可能
  • 演算子のオーバーライドも可能

A Word About Names and Objects

個人的には一読してもピンと来なかったのですが、要はPythonでは変数は全てオブジェクトへの参照だということだと理解しました。なのでもちろんあるオブジェクトへの参照を持った変数を別の変数に代入出来たりもするわけです。JavaSmalltalkに慣れていると当たり前なことなんですが、C++だとオブジェクトへの参照と実体は異なります (←私、これがとても嫌いなんですよね) 。

Python Scopes and Namespaces

PythonにおけるNamespace (名前空間) は特に固有の意味はなく、他のオブジェクト指向言語とまったく同じ意味で使われます。なので名前空間が違えばメソッド名などが同じでも衝突しません。なお、内部的にはオブジェクトの名前を集めた特別なオブジェクト (辞書) です。なので、

z.real


のzはオブジェクトで、realはzの属性 (attribute) ですが、

math.pi


のmathは (モジュール) オブジェクトで、piはmathの属性 (attribute) です。つまりモジュール名も一つのオブジェクトなのです。


なお、モジュールの属性は読み書きの設定が出来ます。書き込み可能な場合は削除も出来ちゃいます。この辺り動的な感じがしますね。削除するとアクセス出来なくなります。なのであんまり使い道がなさそうですね。


モジュールの名前空間 (つまり辞書!) はモジュール定義が読み込まれるタイミングで初期化されます。そしてPythonインタープリターが終了するまで残ります。先ほどモジュールの属性を削除出来ると言いましたが、削除すると名前空間 (辞書) からシンボルが削除されるわけです。なお、__main__モジュールとして実行されたモジュールはグローバル名前空間 (トップレベル) に配置されます。なので属性にアクセスする際にモジュール名を付けなくてもいいわけです。


なお、Pythonではスタックという概念も名前空間として理解出来ます。通常の言語では関数コールでその時のコンテキストがスタックに積まれて、関数から戻ってくるとスタックから戻されます。Pythonでは関数コール時に関数用の名前空間が割り当てられます。そして関数から抜ける時にこの名前空間が破棄される、というわけです。


次にスコープについて。これも他のプログラミング言語と同じ意味です。スコープには以下の3種類あり、この順序でオブジェクトの名前が検索されます。

  • 最下位スコープ: 実行中のブロックのローカル変数
  • 関数内スコープ: 実行中の関数内で定義された変数
  • 最上位スコープ: カレントモジュールで定義された変数
  • ビルドイン名前空間


まぁ、そんなに特殊なスコープではありませんね。なお、オブジェクトのメンバーはこれとは別のローカルな名前空間上に配置されます (特別ってことですね) 。


最後にglobal指定についていろいろ書いてありましたが、いまいちピンと来ません。変数を宣言する時にglobalを付けないとその変数は必ずローカルなスコープの名前空間 (最下位スコープ) に割り当てられる。globalを付けるとカレントモジュールのグローバル変数 (最上位スコープ) に割り当てられるということでしょうかね。ていうことは関数内でも最上位スコープの変数が定義出来ることになりますね。ちょっと試してみましょう。

>>> def test():
...     global g_data
...     g_data = 1
...     print 'test()'
...
>>> test()
test()
>>> g_data
1


確かに出来ました!使い道がよく分かりませんが。。。

A First Look at Classes

さっそくクラスを定義していきましょう。

Class Definition Syntax

クラス定義は簡単に書くとこんな感じになります。

>>> class ClassName:
...     # statement-1
...     # statement-2
...     # ...
...     pass


関数の場合と同様に、何も記述がないとエラーになります。

>>> class ClassName:
...     # statement-1
...     # statement-2
...     # ...
... 
  File "<stdin>", line 5
    
    ^


またちょっと面白いな〜と思ったのが、class定義が終った時点でクラスオブジェクトが作られるわけです。この辺りは次の節で。