読者です 読者をやめる 読者になる 読者になる

Just $ A sandbox

プログラミングと計算機科学とかわいさ

Pythonでsuper(self.__class__, self)は使うな

python

[追記:2013/11/02]
この記事ではPython2.xを前提としていますが、Python3以降はsuperの引数を省略することができるようになっています。
[/追記]

次のPythonコードを見てください。

class A(object):
    def method(self):
        pass
 
class B(A):
    def method(self):
        super(self.__class__, self).method()
 
class C(B):
    def method(self):
        super(self.__class__, self).method()
 
>>> c = C()
>>> c.method()

このコードを実行すると、
RuntimeError: maximum recursion depth exceeded while calling a Python object
すなわち再帰の深さが限界に達したと言われてランタイムエラーが発生します。

C.methodの中のsuperによって渡されたselfオブジェクトは、クラスCのインスタンスです。 よってsuperから呼ばれたB.methodの中ではself.__class__がCと解釈されて、

        super(C, self).method() # => B.methodが呼ばれる

となってしまうのでB.methodがB.methodを呼び、無限再帰になってしまうのです。

これを解消するためにはsuper(B, self).methodのようにクラス名をちゃんと明記するか、A.methodのように直接クラスのメソッドにアクセスします。
また、参考として、こういうハックもあります:

問題点

この問題はあまりメジャーではないのか、super(self.__class__, self)と書いているコードはたくさん見かけます。しかし、これは非常に大きな問題だと思います。

super(self.__class__, self)を使っているクラスを継承してsuper(self.__class__, self)と書いてはいけない。ということを意識してPythonを書いている人がどれだけいるのか?
これといって良い代替案がないことも問題でしょう。「スーパークラスのメソッドを呼ぶこと」と「Aクラスのメソッドを呼ぶこと」は全然意味が違います。それなのにsuperが使いにくいからA.methodと書きなさいというのはいくらなんでもひどすぎではないか?

他に方法があれば教えていただけると嬉しいのですが、いずれにせよsuper(self.__class__, self)の利用は控えたほうがよさそうです。