最近『初めてのRuby』を読んでいる。Pythonのメソッドの第一引数にselfを書かなくてはいけないが、Rubyと対比して理由がなんとなく分かったので検討してみる。

まずPythonではRubyと同様、インスタンスメソッドとトップレベル関数の区別がない。Pythonではメソッドと関数という呼び方をする。関数およびメソッドは単なるオブジェクトの属性である。つまりメソッドはクラスオブジェクトのcallableな属性、関数はモジュールオブジェクトのcallableな属性である。Pythonでも全てがオブジェクトなので、この区別をしないということが重要となる。

ここで、以下のクラス定義を考えてみる。

>>> class Foo : ... a = 1 ... def foo (self): ... a ... Foo.a ... self.a ...

クラス内に関数を定義した場合、ローカル変数(グローバル変数)、クラス変数、インスタンス変数の区別を考えなくてはならない。Rubyでは変数の頭に「何も付けない」、「@を付ける」、「@@を付ける」で構文上区別している。Pythonでは以下のようになる。

1. クラス内で関数を定義すると属性になるので、クラス内で変数を定義しても属性とする

属性なので、Foo.a のような構文で参照させる





2. 次にローカル変数(グローバル変数)とそれ以外のクラス変数、インスタンス変数を区別するため以下のようにする



3. selfをどうにかしないといけない

しかし、Pythonではメソッドと関数の区別がない。メソッド「定義」だけ特殊にしたくない そこで、メソッド(となるべき関数)では「第一引数に自分自身のオブジェクトを表すselfという引数を付ける」という決まりを作る (selfという名前でなくても良い) すると、定義するときにメソッドと関数の区別をする必要がない しかし、メソッド呼び出しの度に第一引数にインスタンスを渡すのは面倒なので、インスタンスからクラス内の関数を参照した場合、第一引数に自動的にインスタンスオブジェクトが渡されてカリー化されたメソッドに自動的に置き換わるという仕組みになっている





ここで、ポイントとしてはRubyのようにselfは省略可とした場合、インスタンス変数に特殊な構文を用意しない限り、ローカル変数とインスタンス変数の区別がつかなくなってしまう。構文上区別しなくても良いが、lookupの規則が複雑になり遅くなる。また同じ変数名が使用できないという制限も付いてしまう。なので通常は違うものであるとして区別したいので、selfを導入するしかない。

4. Rubyのような暗黙のselfはどうだったのか？