2012-05-07 38 views
57

本來我想問問this question,但後來我發現的時候,已經想到過的......Python的延伸 - 使用超()的Python 3比Python的2

周圍的Googling我發現extending configparser這個例子。與Python 3以下工作:

$ python3 
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2 
>>> from configparser import SafeConfigParser 
>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init_(self): 
...   super().__init__() 
... 
>>> cfg = AmritaConfigParser() 

但不是與Python 2:

>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init__(self): 
...   super(SafeConfigParser).init() 
... 
>>> cfg = AmritaConfigParser() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __init__ 
TypeError: must be type, not classob 

然後我讀Python的新類與舊類樣式一點點(如here 現在我。我想,我可以這樣做:

class MyConfigParser(ConfigParser.ConfigParser): 
     def Write(self, fp): 
      """override the module's original write funcition""" 
      .... 
     def MyWrite(self, fp): 
      """Define new function and inherit all others""" 

但是,我不應該叫初始化這是在Python 2等價的:?

class AmritaConfigParser(ConfigParser.SafeConfigParser): 
    #def __init__(self): 
    # super().__init__() # Python3 syntax, or rather, new style class syntax ... 
    # 
    # is this the equivalent of the above ? 
    def __init__(self): 
     ConfigParser.SafeConfigParser.__init__(self) 
+1

在你的榜樣,你不需要定義一個'__init __()'的子類,如果它是所有調用超類'__init __()'(以Python 2或3) - 而是讓超級繼承。 – martineau

+0

有用的參考資料:http://amyboyle.ninja/Python-Inheritance/ –

回答

99
  • super()(不帶參數)在Python 3引入(連同__class__):

    super() -> same as super(__class__, self) 
    

    所以這將是Python的2當量新樣式類:

    super(CurrentClass, self) 
    
  • 您可以隨時使用的舊式課程:

    class Classname(OldStyleParent): 
        def __init__(self, *args, **kwargs): 
         OldStyleParent.__init__(self, *args, **kwargs) 
    
+1

-1。這個答案沒有爲我澄清任何事情。在Python 2中,'super(__ class __)'給出了'NameError:全局名'__class__'未定義','super(self .__ class __)'也是錯誤的。你*必須*提供一個實例作爲第二個參數,這意味着你需要做'super(self .__ class__,self)',但這是錯誤的**。如果'Class2'繼承自'Class1'並且'Class1'調用'super(self。__class__,self).__ init __()','Class1'''__init__'然後*在實例化'Class2'的實例時調用它自己*。 – jpmc26

+0

爲了澄清一點,當試圖在Python 2中調用'super(self .__ class __)'時,我得到'TypeError:super()至少需要1個參數(0給出)'。(這沒有什麼意義)但是它顯示了這個答案中缺少多少信息。) – jpmc26

+2

@ jpmc26:在python2中,你得到這個錯誤是因爲你試圖調用'__init __()'而沒有綁定超級對象的參數(通過調用'super( self .__ class __)'只有一個參數),你需要一個綁定的超級對象,那麼它應該工作:'super(CurrentClass,self).__ init __()'。不要使用'self .__ class__',因爲在調用父類時它總是引用_same_類,因此如果該父類也執行相同的操作,則會創建一個無限循環。 – mata

28

在單個繼承的情況下(當您僅繼承一個類時),您的新類將繼承基類的方法。這包括__init__。所以如果你沒有在你的課堂上定義它,你會從基地獲得。

如果您引入多重繼承(每次繼承一個以上的類),事情就會變得複雜起來。這是因爲如果不止一個基類有__init__,你的類將只繼承第一個基類。

在這種情況下,如果可以的話,您應該真的使用super,我會解釋原因。但並不總是你可以。問題是你所有的基類都必須使用它(以及它們的基類 - 整棵樹)。

如果是這樣的話,那麼這也將正常工作(在Python 3,但你可以返工成Python 2 - 它也有super):

class A: 
    def __init__(self): 
     print('A') 
     super().__init__() 

class B: 
    def __init__(self): 
     print('B') 
     super().__init__() 

class C(A, B): 
    pass 

C() 
#prints: 
#A 
#B 

聲明同時基類如何使用super即使他們沒有自己的基類。

super所做的是:它從MRO中的下一個類(方法解析順序)調用方法。 C的MRO是:(C, A, B, object)。您可以打印C.__mro__以查看它。

所以,CA.__init__電話B.__init__B遵循MRO A)繼承Asuper__init__

因此,通過在C中無所事事,您最終會調用兩者,這正是您想要的。現在

,如果你沒有使用super,你最終會繼承A.__init__(如前),但這次沒有任何東西會叫B.__init__你。

class A: 
    def __init__(self): 
     print('A') 

class B: 
    def __init__(self): 
     print('B') 

class C(A, B): 
    pass 

C() 
#prints: 
#A 

爲了解決這個問題,你必須定義C.__init__

class C(A, B): 
    def __init__(self): 
     A.__init__(self) 
     B.__init__(self) 

但問題是,在更復雜的MI的樹木,有些類可能最終的__init__方法被調用一次,而超多/ MRO保證他們只被調用一次。

+7

'請注意,即使基類沒有自己的基類,兩個基類都使用超類。「他們有。在py3k中,每個類的子類都是對象。 – akaRem

15

總之,它們是等價的。我們有一個歷史視圖:

(1)起初,函數看起來像這樣。 (2)使代碼更抽象(並且更便於攜帶)。獲得超一流的常用方法是發明出來的:

super(<class>, <instance>) 

和初始化函數可以是:

class MySubClassBetter(MySuperClass): 
     def __init__(self): 
      super(MySubClassBetter, self).__init__() 

但是需要類和實例二者的明確傳球打破DRY(別重複你自己)規則一點。 (3)在V3中,可以使用以下公式(3):

(3)。它更智能,

super() 

在大多數情況下是足夠的。你可以參考http://www.python.org/dev/peps/pep-3135/

0

只是爲了一個Python 3的簡單和完整的例子,大多數人似乎現在正在使用它。

class MySuper(object): 
    def __init__(self,a): 
     self.a = a 

class MySub(MySuper): 
    def __init__(self,a,b): 
     self.b = b 
     super().__init__(a) 

my_sub = MySub(42,'chickenman') 
print(my_sub.a) 
print(my_sub.b) 

42 
chickenman