Pythonのメソッド引数に self を書くメリット
なぜPythonのメソッド引数に明示的にselfと書くのか に関連して。
確かに他の言語から移ってきた人からすると奇異に見えることが多そうですね。ただ、私はこの仕様を知ったとき「上手いな」と思いました。
というのも、
instance.method(arguments) == ClassName.method(instance, arguments)
これが成り立つ事によって、メソッドをコールバック関数として渡すのが非常に簡単になるのです。
つまり
class MyClass: def __init__(self, n): self.name = n def getname(self): return "name: " + self.name entities = [MyClass("A"), MyClass("B"), MyClass("C")] names = map(MyClass.getname, entities) # ["name: A", "name: B", "name: C"] が返される
という事ができてしまうのです。
JavaScriptでこれができないために以前エントリを書きました([id:gakuzo:20090403:1238715610])が、Python ではこの self の仕様のため簡単に実現できます。これは非常に魅力的。
ただ、Python のこの仕様にも問題があります。それは、ポリモーフィックには動作しないということ。
コードで例を示すと
class SuperClass: def __init__(self, n): self.name = n def getname(self): return "super: " + self.name class Sub1Class(SuperClass): def getname(self): # override return "sub1: " + self.name class Sub2Class(SuperClass): def getname(self): # override return "sub2: " + self.name entities = [Sub1Class("A"), Sub1Class("B"), Sub2Class("C"), Sub2Class("D")] # entities の各要素の getname を呼んで ["sub1: A", "sub1: B", "sub2: C", "sub2: D"] という値が欲しい。 names1 = map(SuperClass.getname, entities) # ["super: A", "super: B", "super: C", "super: D"] になる。 names2 = map(Sub1Class.getname, entities) # ["sub1: A", "sub1: B", "sub1: C", "sub1: D"] になる。 names3 = map(Sub2Class.getname, entities) # ["sub2: A", "sub2: B", "sub2: C", "sub2: D"] になる。
どうやっても上手くいきません。結局 lambda で書く必要があります。
仕組みを考えれば当たり前の話ではあるのですが、残念感が残りますね。この辺をスマートに解決してる言語をご存知の方がいらっしゃればご教授ください。
Ruby ぐらいブロックが簡潔に書ければそもそもこんな仕組みは必要ない気もしますが。