2016-04-28 120 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

「一個未知的深度」聽起來像一個壞對象設計。 – 2016-04-28 15:06:49

+0

@DisplayName:「未知深度」意味着代碼會隨着時間的推移而增長。就我而言,代碼是一個測試套件,其中一些測試從現有測試繼承,並覆蓋或擴展現有方法。此外,每個測試預計會有六個預定義的方法,這些方法是從測試框架以特定方式調用的。 –

+0

...基本上,2.x沒有__this_class__的代詞。 –

回答

1

正如你已經發現了利用type(self)導致遞歸因爲Baz.__init__針對Bar.__init__但在那裏,你想請致電super(Baz, self).__init__,這又是Bar.__init__,所以您最終得到無限遞歸。

通常情況下,您只需調用父母而不知道您調用的是哪個類實例,因爲否則您需要真正知道並修復您的MRO。你總是可以找到兒童類中調用與self.__class__self.__class__.__name__

解決它的方法很簡單:用替換您super -calls:

super(Bar, self).__init__() 

在python3避免這些(主要是不必要的)硬編碼在超類它也可以使用:

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 __()'有效,但它還遠遠不夠,我不想重複該類名字,我想要一個代名詞,但是感謝一個非常明確的解釋。 –