2016-04-28 7 views
1

クラスのメソッドでは、オブジェクトのクラスではなくメソッドが定義されているクラスのsuper()を呼び出す必要があります。私は特にPython 2.xを気にしますが、3.xのソリューションは大歓迎です。このコードはどのクラスで定義されていますか?

あるクラスが別のクラスを継承し、未知の深さまでプロジェクト全体で使用できる一般的な定型文を作成したいと考えています。再帰エラーを避けるには、コードが定義されている現クラスの親クラスを呼び出す必要があります。selfオブジェクトの親ではありません。多くのメソッドが拡張されているので、現在のクラス名が参照される各モジュールにはいくつかの場所があり、各拡張メソッドは親クラスメソッドを呼び出すことができます。ここで

#!/usr/bin/env python 

from inspect import stack 

class Foo(object): 
    def __init__(self): 
     print "Foo.__init__()" 
     print "file: %s" % __file__ 
     print "class: %s" % self.__class__.__name__ 
     print "stack: %s" % stack()[0][3] 
     print 

class Bar(Foo): 
    def __init__(self): 
     print "Bar.__init__()" 
     super(type(self), self).__init__() 

class Baz(Bar): 
    pass 


foo = Foo() 
bar = Bar() 
baz = Baz() 

が結果です:

はここで失敗したデモです

Foo.__init__() 
file: ./class.py 
class: Foo 
stack: __init__ 

Bar.__init__() 
Foo.__init__() 
file: ./class.py 
class: Bar 
stack: __init__ 

Bar.__init__() 
Bar.__init__() 

# snip several hundred lines 

Bar.__init__() 
Bar.__init__() 
Traceback (most recent call last): 
    File "./class.py", line 24, in <module> 
    baz = Baz() 
    File "./class.py", line 16, in __init__ 
    super(type(self), self).__init__() 

# snip several hundred lines 

    File "./class.py", line 16, in __init__ 
    super(type(self), self).__init__() 
    File "./class.py", line 16, in __init__ 
    super(type(self), self).__init__() 
RuntimeError: maximum recursion depth exceeded while calling a Python object 
+0

「未知の深さには、」悪いオブジェクト設計のように聞こえます。 –

+0

@DisplayName:「未知の深さまで」とは、コードが時間とともに成長することを意味します。私の場合、コードはテストスイートであり、既存のテストから継承したいくつかのテストと、既存のメソッドをオーバーライドまたは拡張しています。さらに、各テストは、テストフレームワークから特定の方法で呼び出される半ダースの事前定義されたメソッドを持つことが期待されます。 –

+0

...基本的に、2.xには__this_class__の代名詞はありません。 –

答えて

1

あなたはすでにtype(self)Baz.__init__Bar.__init__に向けられているが、そこにあなたがしたいので、再帰につながる使用していたようsuper(Baz, self).__init__にもう一度Bar.__init__を呼び出して、無限回帰になります。

一般的には、呼び出すクラスインスタンスを知らなくても親を呼び出すのが一般的です。そうしないと、実際にあなたのMROを知り、修正する必要があるからです。これらの(ほとんど不要)ハードコードを避けるためのpython3で

super(Bar, self).__init__() 

:であなたのsuper -callsを交換してください:あなたは非常に簡単である子クラスにそれを解決self.__class__self.__class__.__name__

と呼ばれる方法常に見つけることができます

常にその私 親クラスのメソッドを呼び出します
super().__init__() 

:スーパー、それは使用することも可能です内のクラスのそれを埋める。あなたの現在のクラスの親クラスが、スーパーコールによって解決された次の親クラスでないケースはほとんどありません。

出力は(__file__が欠落しているもの)を次のようになります。

Foo.__init__() 
class: Foo 
stack: __init__ 

Bar.__init__() 
Foo.__init__() 
class: Bar 
stack: __init__ 

Bar.__init__() 
Foo.__init__() 
class: Baz 
stack: __init__ 
+0

これは関連性があります。http://stackoverflow.com/questions/5033903/python-super-method-and-calling-alternatives –

+0

@BiRico私は 'super'を一貫して使用しています。これは線形継承であり、それほど重要ではありません。しかし確かに読む価値がある。私はそれを楽しんでいましたが、今私はそれ以上のことに「スーパー」を信頼していません。奇妙なもの...それはおそらく後方互換性のために変更されることはありません:-(リンクをありがとう! – MSeifert

+0

私が暗示しているが、綴りに失敗した、私はしたくないです現在のクラスの名前をコード全体(2.xの中)に振りかけるので、 'super(Bar、self).__ init __()'は動作しますが、それほど遠くはありません。名前、私はそれのための代名詞が欲しいですが、非常に明確な説明に感謝します。 –

関連する問題