2013-07-10 69 views
7

可正常工作:爲什麼classmethod的super需要第二個參數?

>>> class Foo(object): 
... @classmethod 
... def hello(cls): 
...  print 'hello, foo' 
... 
>>> class Bar(Foo): 
... @classmethod 
... def hello(cls): 
...  print 'hello, bar' 
...  super(Bar, cls).hello() 
... 
>>> b = Bar() 
>>> b.hello() 
hello, bar 
hello, foo 

我也可以調用基類明確:

>>> class Bar(Foo): 
... @classmethod 
... def hello(cls): 
...  print 'hello, bar' 
...  Foo.hello() 
... 
>>> b = Bar() 
>>> b.hello() 
hello, bar 
hello, foo 

我想知道爲什麼我不能省略的第一個參數super,像這樣:

>>> class Bar(Foo): 
... @classmethod 
... def hello(cls): 
...  print 'hello, bar' 
...  super(Bar).hello() 
... 
>>> b = Bar() 
>>> b.hello() 
hello, bar 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in hello 
AttributeError: 'super' object has no attribute 'hello' 

當沒有第二個參數的super調用的結果看起來像是一個超類型的類類型:

>>> class Bar(Foo): 
... @classmethod 
... def hello(cls): 
...  print Foo, type(Foo) 
...  print super(Bar), type(super(Bar)) 
...  print cls, type(cls) 
... 
>>> b = Bar() 
>>> b.hello() 
<class '__main__.Foo'> <type 'type'> 
<super: <class 'Bar'>, NULL> <type 'super'> 
<class '__main__.Bar'> <type 'type'> 

我想我只是想知道這裏的設計。爲什麼我需要將類對象傳入超級調用以獲取對基類類型Foo的引用?對於常規方法,將self傳遞給函數是有意義的,因爲它需要將基類類型綁定到該類的實際實例。但是classmethod不需要該類的特定實例。

編輯: 我得到的Python 3.2相同的錯誤,因爲我在上面2.7 super(Bar).hello()做。不過,我可以簡單地做super().hello(),這工作正常。

+0

在python 3.x中它們修復了超級調用...在python2x中,它們只是沒有認爲它通過那麼多(我的猜測是......)無論如何,我認爲這將最終關閉如「爲什麼」的問題通常是... –

+0

您可能會發現這個有用:http://stackoverflow.com/questions/11354786/super-confusing-python-multiple-inheritance-super?rq=1 – mdscruggs

+0

@JoranBeasley咩,我已經問過幾個爲什麼類型的問題還沒有結束。 – jterrace

回答

7

super()返回descriptor,並且需要兩個項目:

  • 一個出發,從中搜索類層次結構點。
  • 參數綁定返回的方法。

對於這兩個參數(以及隱含零參數*)的情況下的第二個參數被用於結合,但是如果不以第二參數傳遞,super()不能調用描述符協議綁定返回的函數,類方法,屬性或其他描述符。 classmethods仍然是描述符並且被綁定;綁定到類而不是實例,但super()不知道描述符將如何使用您綁定到的上下文。

super()不應該也不能知道你正在查找類方法而不是常規方法;類方法僅與常規方法不同,因爲它們的方法行爲不同。

爲什麼要綁定類方法?因爲當你繼承Foo但做覆蓋.hello(),稱Bar.hello()調用Foo.__dict__['hello']功能,它結合Bar和你的第一個參數hello(cls)將是子類,不Foo

沒有第二個參數,super()返回一個未綁定的對象,以後可以手動將其綁定。你可以使用由super()實例提供的.__get__()方法結合自己:

class Bar(Foo): 
    @classmethod 
    def hello(cls): 
     print 'hello, bar' 
     super(Bar).__get__(cls, None).hello() 

super().__get__()上的實例,不需要上下文有效地返回一個新的super()實例與設定的範圍內。在具有上下文.__get__()的實例僅返回self;它已經受到約束。


*在Python 3,呼籲super()不帶參數從綁定的方法將使用調用框架探索,含蓄,什麼類型和綁定的對象都在裏面,所以你不再需要明確地傳遞在這種情況下的類型和對象參數。爲此,Python 3實際上爲方法增加了一個隱含的閉包變量。請參閱PEP 3135Why is Python 3.x's super() magic?

相關問題