pythonでは、インスタンスの作成で、new演算子を使いません。
というか、「new演算子」という構文が存在しません。
PHPやJavaやらCやらの経験者からすると、
これはやや気持ち悪い。
具体的には小生がそうでした。
ただし、その方法論が腑に落ちると、「new「演算子」」のある言語が「オブジェクト指向言語」に見えなくなってきます。少なくとも小生はそうです。
順番に行きましょう
pythonでは、普通の言語でいうところの「クラス宣言」は有りません。
しかし、同等の機構はあります。クラスオブジェクトの作成です。
http://www.python.jp/doc/2.4/tut/node11.html#SECTION0011320000000000000000
下記の例で言うと、anyclass変数に、クラスオジェクトが入ります。
@staticmethodデコレータを挟むだけです。
フツーの関数宣言は、selfが必要ですが、今度は逆に、selfを入れると怒られます。pythonは、selfを引数に勝手に加えるのを辞めます。staticmethodは、そういうマーキングをやってるらしい。この状態では、method1を直接呼び出すことができます。 http://docs.python.org/c-api/structures.html#METH_STATIC
statichas.method1()
ただしこれでは問題が無くもありません。関数の中からは、クラスもインスタンスも解らないので、クラス内の他のメソッドも使えません。
#逆に、一人完結してます。というアピールに#@staticmethodを使うのは、筆者はアリだと思います。
前述のクラスメソッド表記で呼び出せなくもありませんが、クラスを継承する状況を想定すると、固定で書くのは避けたいですね。
ハイ。そこで出てくるのは、@classmethodデコレータです。フツーの言語の、静的メソッドに相当するのは、むしろコッチでしょう。
「「インスタンスオブジェクト」で無いモノ」を付けてね」という意味です。らしい。http://docs.python.org/c-api/structures.html#METH_CLASS 前述のtype型インスタンスなので、歴史的&一般的にselfとは付けません。世間一般にはclsとだけ付けるっぽいですが、小生は3文字変数に辛い思い出があるので、"cls1"にしてます。
しかも継承すれば、継承後のクラスオブジェクトがcls1に入っている。
という寸法です。
面白い発想ですね。
具体的には、app engine python-SDKのgoogle.appengine.ext.db.Model.get がlassmethodです。小生は、この辺りの実装を眺めていて、感動すら覚えました。
class「定義」の構文は、フツーの関数定義を「メソッド呼び出しに変換する」処理であると考えれば、腑に落ちると思います。故に、$thisを暗黙で「渡さない」方が何かと都合が良いわけです。
これを利用して、定義済みクラスじゃなくてtypeオブジェクトに、メソッドを後付けできます。「class定義」がコンパイラの仕事じゃないから出きることですね。真の動的言語の何たるかを見た気がします。
そんな訳ですので、フツーのインスタンスメソッドから、classmethodを使うときにはどうするか?構文を区別する必要があります。
今まで、インスタンス作成、メソッド呼び出し、と色々述べましたが、
表記上の違いはほとんどありませんし、Python内部でのメカニズムの違いも殆どありません。 他の言語でいうところの「クラス定義」は、「タイプ型オブジェクト」でしかないので、「◯◯オブジェクトのメンバ関数を呼ぶ」という機構は統一できてるわけです。
呼び出し可能なオブジェクト(特にcallableと呼ぶ)を、呼んでる(call)だけ。
これに付きます。
これが腑に落ちると、途端に「new演算子のあるオブジェクト指向言語」が駄目言語に見えます。
筆者はここまで徹底したオブジェクト指向を他に知りません。
#ご存知の方は、教えてくれなくてもいいです。長くなりそうなんで。
識者が言うところによると、pythonは、広義には関数型言語らしい。
haskelには気絶しそうになりましたが、大分判りやすくて助かります。
というか、「new演算子」という構文が存在しません。
PHPやJavaやらCやらの経験者からすると、
これはやや気持ち悪い。
具体的には小生がそうでした。
ただし、その方法論が腑に落ちると、「new「演算子」」のある言語が「オブジェクト指向言語」に見えなくなってきます。少なくとも小生はそうです。
順番に行きましょう
pythonでは、普通の言語でいうところの「クラス宣言」は有りません。
しかし、同等の機構はあります。クラスオブジェクトの作成です。
http://www.python.jp/doc/2.4/tut/node11.html#SECTION0011320000000000000000
下記の例で言うと、anyclass変数に、クラスオジェクトが入ります。
class anyclass(object): pass
インスタンスの作成はどうするかというと、作って有るはずの、クラスオブジェクトをcallしてるわけです。だからnew演算子を付けちゃいけません。「呼んでる」だけだから。
もちろんこんな空っぽのクラスは何の役にもたちません。とりあえずメソッドを足します。
pythonは、言語としては珍しく、メソッドの引数として「自分インスタンスオブジェクト」を第1引数に書かなければなりません。
インスタンスを作ると、クラスメソッドとインスタンスオブジェクトが結びつきます。
ここでのポイントは、
instance1.method1() と、hasmethod.method1() は別物である。
ということです。
インスタンスオブジェクトをどうにかして渡す必要があります。
それで第1引数 self の出番というわけです。
前者は、「結びついてる」ので、pythonがselfを勝手に足してくれます。故に、インスタンス関数呼び出しでは、self 以外の引数だけを書くわけです。
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):引数に必ず1個入ります。わざわざclassmethodと付けたのは意味がもちろんあって、
@classmethod
def method1(cls1):pass
「「インスタンスオブジェクト」で無いモノ」を付けてね」という意味です。らしい。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です。小生は、この辺りの実装を眺めていて、感動すら覚えました。
これを利用して、定義済みクラスじゃなくて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には気絶しそうになりましたが、大分判りやすくて助かります。