2013-07-10 8 views
7

इस रूप में की उम्मीद काम करता है:क्लासमेड के सुपर को दूसरी तर्क की आवश्यकता क्यों है?

>>> 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 पास करना समझ में आता है, क्योंकि इसे कक्षा के वास्तविक उदाहरण में बेस क्लास प्रकार को बांधना होगा। लेकिन एक वर्ग विधि को कक्षा के विशिष्ट उदाहरण की आवश्यकता नहीं है।

संपादित: मैं अजगर 3.2 में एक ही त्रुटि मिलती है के रूप में मैं super(Bar).hello() के लिए 2.7 में ऊपर है। हालांकि, मैं बस super().hello() कर सकता हूं और यह ठीक काम करता है।

+0

पायथन 3.x में वे सुपर कॉल को थोड़ा सा ठीक करते हैं ... python2x में उन्होंने अभी तक इतना नहीं सोचा था (मेरा अनुमान है ...) मुझे लगता है कि यह बंद होने जा रहा है जैसा कि "क्यों" प्रश्न आमतौर पर होते हैं ... –

+0

आपको यह उपयोगी मिल सकता है: http://stackoverflow.com/questions/11354786/super-confusing-python-multiple-inheritance-super?rq=1 – mdscruggs

+0

@ जोरनबेस्ले मेह, मैं मैंने कई कारणों से पूछा है कि इससे पहले कि बंद नहीं किया गया है। – jterrace

उत्तर

7

super() रिटर्न एक descriptor, और दो आइटम की जरूरत है:

  • जहाँ से वर्ग पदानुक्रम खोज करने के लिए एक प्रारंभिक बिंदु।
  • पर तर्क बाध्य विधियों को बांधें।

दो तर्क (और निहित शून्य तर्क *) मामले के लिए दूसरा तर्क करने के लिए बाध्य करने के लिए प्रयोग किया जाता है, लेकिन अगर आप एक दूसरा तर्क में उत्तीर्ण नहीं होते हैं, super() बाध्य करने के लिए वर्णनकर्ता प्रोटोकॉल को लागू नहीं किया जा सकता कार्यों, वर्ग विधि, गुण या अन्य वर्णनकर्ता लौटा दिया। classmethods अभी भी वर्णनकर्ता हैं और बाध्य हैं; एक वर्ग से बंधे और एक उदाहरण नहीं, लेकिन super() नहीं जानता कि वर्णनकर्ता किस संदर्भ को संदर्भित करेगा उसका उपयोग करेगा।

super() यह नहीं जानना चाहिए कि आप एक नियमित विधि के बजाय कक्षा विधि देख रहे हैं; वर्ग विधियां केवल नियमित तरीकों से भिन्न होती हैं क्योंकि उनकी .__get__() विधि अलग-अलग कार्य करती है।

कक्षा के तरीके क्यों बंधे हैं? क्योंकि जब आप Foo उपवर्ग लेकिन नहीं ओवरराइड .hello(), Bar.hello() बुला invokes 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 लौटाता है; यह पहले से ही बाध्य है।


* अजगर 3 में, एक बाध्य विधि, किस प्रकार और बाध्य वस्तु हैं खोज करने के लिए, परोक्ष बुला फ्रेम का उपयोग करेगा अंदर से तर्क के बिना super() बुला, इसलिए तुम अब स्पष्ट रूप में पारित करने के लिए है उस मामले में प्रकार और वस्तु तर्क। पायथन 3 वास्तव में इस उद्देश्य के लिए विधियों को बंद करने के लिए एक अंतर्निहित __class__ बंद चर शामिल करता है। देखें PEP 3135 और Why is Python 3.x's super() magic?

संबंधित मुद्दे