メソッドのself (2)

メソッドのselfに関して再考してみる。selfをなくすためにPythonに互換性を持たせる必要があるということは、ここでは無視する。


Guidoのself必要という理由は以下の3つ。

  • foo.meth(arg) == C.meth(foo, arg)が成り立つ
  • 関数をメソッドにできる
  • メソッドがデコレートされたときに,self引数が渡されるかどうかを知ることはできない


正直デコレータの時に何が問題かが分からない。selfにインスタンスが渡されたのか、クラスが渡されたのかが判別できないということだろうか?そうだとすれば判別の必要あるのだろうか?そもそも私はPythonでクラスメソッドをほとんど使用しない。クラスメソッド自体必要ないのではないか?以下のようにしてみてはどうだろう?

  • メソッド定義時にselfを引数で渡す必要ない
  • 関数(メソッド)内でキーワードselfが使用可能
  • レシーバ(メソッドを呼び出すオブジェクト)がクラスであればselfにクラスオブジェクトが入る
  • レシーバがインスタンスであればselfにインスタンスオブジェクトが入る
  • クラス変数は、「クラス名.属性」でアクセス。インスタンス変数は、「self.属性」でアクセス。ローカル/グローバル変数は「変数名」でアクセス


Python処理系の実装としては、クラスのメソッドを定義すると、selfを第一引数に渡したもののシンタックスシュガーにすれば良いと思う。しかし互換性は崩れる。上記3つの問題も、meth内でselfを使用したときにはAttributeErrorが発生し、foo.meth(arg) != C.meth(arg)で、meth内でselfを使用しなければ==が成り立つ。foo.meth(arg) == C.meth(foo, arg)はそもそも意味ないと思う。関数をメソッドにするのも問題ないと思う。デコレータに関しては、self引数は必ず渡されないので区別する必要ないと思われる。


ルールに関しても複雑になるとは思わない。単に互換性だけだと思う。問題のあるコード例がないので見逃している点が良く分からない。もちろん今のPythonだとselfを消すのは実現できないが、以下のように試すことはできる。

>>> def self_deco(func):
...     def func2(self, arg):
...        return func(arg)
...     return func2
...
>>> class C:
...     def __init__(self):
...         C.self = self
...     @self_deco
...     def foo(arg):
...         C.self.v = arg
...         return C.self.v 
...
>>> c = C()
>>> c.foo(1)
1
>>> c.v
1

追記(2008/11/28):
上記の例はインスタンスオブジェクトをクラス変数のC.selfに保存しているのでマルチプルインスタンスには対応していない。


インスタンス変数にアクセスする時に、selfを明示的に指定する必要があるというの良いルールだと思う。foo.methの時に第一引数がカリー化されるのであれば、def meth(arg)をdef meth(self, arg)のシンタックスシュガーにするというアイデアは悪くないのではないだろうか?繰り返すが、もちろんselfの意味は文脈により決定される。もしかして、ここが実装が複雑になるのかな?しかし、レシーバにオブジェクトが書いてあるので難しくはない気がする。継承も関係ないと思うし。互換性以外には何が問題なのだろう?