メソッドのself (2)
メソッドのselfに関して再考してみる。selfをなくすためにPythonに互換性を持たせる必要があるということは、ここでは無視する。
- 和訳 : なぜPythonのメソッド引数に明示的にselfと書くのか (http://coreblog.org/ats/translation-of-why-explicit-self-has-to-stay)
- メソッドのself (http://d.hatena.ne.jp/morchin/20080923#p1)
- Self in the Argument List: Redundant is not Explicit (http://www.artima.com/weblogs/viewpost.jsp?thread=239003)
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の意味は文脈により決定される。もしかして、ここが実装が複雑になるのかな?しかし、レシーバにオブジェクトが書いてあるので難しくはない気がする。継承も関係ないと思うし。互換性以外には何が問題なのだろう?