2010-09-28 14 views
13

निम्नलिखित कोड नमूना के साथ, super का उपयोग किया जा सकता है, या C को A.foo और B.foo पर स्पष्ट रूप से कॉल करना है?एक ही विधि नाम के साथ विभिन्न पथों से पायथन एकाधिक विरासत

class A(object): 
    def foo(self): 
     print 'A.foo()' 

class B(object): 
    def foo(self): 
     print 'B.foo()' 

class C(A, B): 
    def foo(self): 
     print 'C.foo()' 
     A.foo(self) 
     B.foo(self) 

उत्तर

8

super() ही कभी, किसी दिए गए विधि के लिए एक एकल वर्ग प्रकार का समाधान हो जाएगा, इसलिए यदि आप कई वर्गों से इनहेरिट रहे हैं और उन दोनों में विधि कॉल करना चाहते हैं, तो आप ' इसे स्पष्ट रूप से करने की आवश्यकता होगी।

+0

उत्तर के लिए धन्यवाद। अब मैं सुपर() का उपयोग न करने के लिए अब गंदा महसूस नहीं करता हूं। – sayap

+4

स्पष्ट रूप से बेस क्लास विधियों को कॉल करते समय * प्रश्नकर्ता के उदाहरण जैसे बहुत ही सरल परिदृश्यों के लिए काम कर सकते हैं, यदि आधार वर्ग स्वयं एक सामान्य आधार से प्राप्त होते हैं तो आप टूट जाएंगे और आप नहीं चाहते कि अंतिम बेस क्लास की विधि को दो बार बुलाया जाए । इसे "हीरा विरासत" के रूप में जाना जाता है और यह कई एकाधिक विरासत प्रणालियों (जैसे सी ++ में) के लिए एक बड़ी समस्या है। पायथन की सहयोगी एकाधिक विरासत ('सुपर() 'के साथ) आपको कई मामलों में आसानी से हल करने देती है (हालांकि यह कहना नहीं है कि एक सहकारी एकाधिक विरासत पदानुक्रम डिजाइन करना आसान है या हमेशा एक अच्छा विचार है)। आत्मनिरीक्षण – Blckknght

4

आप निम्नलिखित जोड़ा है:

class A(object): 
    def foo(self): 
     print 'A.foo()' 

class B(object): 
    def foo(self): 
     print 'B.foo()' 

class C(A, B): 
    def foo(self): 
     super(C, self).foo() 
     print 'C.foo()' 
     A.foo(self) 
     B.foo(self) 


c = C() 
c.foo() 
सुपर

तब (सी, आत्म) .foo()

A.foo के उत्पादन

A.foo() 
C.foo() 
A.foo() 
B.foo() 

है संदर्भित करता है [संपादित करें: अतिरिक्त जानकारी और लिंक शामिल करें]

+0

हाँ, यह मेरा प्रश्न था। तो इस मामले के लिए सुपर का मतलब नहीं है? – sayap

+0

@ सैयाप: मैंने अपने उत्तरों को उन लिंक को शामिल करने के लिए संपादित किया है जो समझने के लिए प्रासंगिक हैं कि सुपर काम कैसे करता है। यह काम करता है लेकिन यह पहले एफू पाएगा और अगर बीएफयू से एफू नहीं था तो उसे देखा जाएगा। – pyfunc

+0

मैं एफू() को दो बार क्यों बुलाऊंगा? – sayap

6

सुपर "पहली" सुपर वर्ग पर foo विधि कॉल करेंगे। इस वर्ग C के लिए विधि संकल्प आदेश (__mro__) पर आधारित है।

>>> C.__mro__ 
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>) 
>>> 

इसलिए यदि आप super(C, self).foo() फोन, A.foo कहा जाता है। यदि आप विरासत आदेश को class C(B, A): में बदलते हैं तो यह उलट दिया जाता है। __mro__ अब लगता है कि:

>>> C.__mro__ 
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>) 
>>> 

यह परिवर्तन करने के बाद super(C, self).foo() कॉल करते हैं, B.foo() कहा जाता हो जाएगा।

+0

yay मुझे लगता है कि यह स्वीकार किए गए एक से अधिक जानकारीपूर्ण उत्तर है। क्या आप इस काम को करने के लिए सामान्य आधार वर्ग की आवश्यकता क्यों कर सकते हैं? –

19

super वास्तव में इस स्थिति के लिए है, लेकिन यह केवल काम करता है अगर आप इसे लगातार इस्तेमाल करते हैं। सभी का उपयोग आधार वर्ग भी नहीं करते हैं super यह काम नहीं करेगा, और जब तक विधि object में है आप super कॉल की श्रृंखला समाप्त करने के लिए एक आम आधार वर्ग की तरह कुछ का उपयोग करने के लिए है।

class FooBase(object): 
    def foo(self): pass 

class A(FooBase): 
    def foo(self): 
     super(A, self).foo() 
     print 'A.foo()' 

class B(FooBase): 
    def foo(self): 
     super(B, self).foo() 
     print 'B.foo()' 

class C(A, B): 
    def foo(self): 
     super(C, self).foo() 
     print 'C.foo()' 

@Marcin पूछता क्यों एक आम आधार हो गया है:

FooBase कि foo लागू करता है लेकिन super() फोन नहीं करता आखिरी वर्ग super() फोन है कि एक विशेषता त्रुटि प्राप्त होगी क्योंकि वहां कोई बिना कॉल करने के लिए आधार विधि।

अगर वहाँ अलग आधार वर्ग थे class A(AFooBase): और class B(BFooBase):A में super() कॉल AFooBase में विधि और B में विधि के नाम से जाना कभी नहीं होगा कहेंगे। जब आधार सभी वर्गों के लिए आम है, तो यह विधि समाधान आदेश के अंत तक जाता है और आप निश्चित हो सकते हैं कि कक्षा वर्ग को परिभाषित करने के लिए कक्षाओं को परिभाषित करने के लिए कोई फर्क नहीं पड़ता है।

+0

के लिए – Marcin

+0

@marcin आपको सुपर() काम करने के लिए एक सामान्य आधार की आवश्यकता नहीं है। @ डंकन बस यह दर्शाता है कि हीरा-विरासत से निपटने के दौरान कितना सुपर() बेहतर होता है। और वैसे, 'सी()। Foo() 'कॉल करने का आउटपुट' बीएफयू() एफू() होगा। "ए .. बी .. सी .." ऑर्डर के बजाय सीएफ() ', और कारण एमआरओ [मनोज के उत्तर] में व्याख्या कर रहा है (http://stackoverflow.com/a/3810465/728675) – RayLuo

+0

@RayLuo यह जवाब सचमुच कहता है कि एक आम आधार की आवश्यकता है – Marcin

0

यह super

class A(object): 
    def foo(self): 
     print 'A.foo()' 

class B(object): 
    def foo(self): 
     print 'B.foo()' 

class C(A, B): 
    def foo(self): 
     print 'C.foo()' 
     super(C, self).foo() # calls A.foo() 
     super(A, self).foo() # calls B.foo() 
+0

तो आप 'सुपर (सी, स्वयं) .foo()' या 'सुपर (ए, स्वयं) .foo()' को 'एफू()' या 'बीएफयू()' के बजाय कॉल करके क्या हासिल करते हैं। ? – FooF

1

के साथ संभव है डंकन जैसा कि ऊपर कहा खासकर यदि आप सुपर() लगातार का उपयोग आप उम्मीद के मुताबिक परिणाम प्राप्त कर सकते हैं।

निम्न परीक्षण से परिणाम सहायक थे: उन सभी के इस सूत्र के लिए योगदान दिया के लिए

>>> c = C() 
>>> c.foo() 
C.foo() before super() 
A.foo() before super() 
B.foo() before super() 
FooBase.foo() 
B.foo() after super() 
A.foo() after super() 
C.foo() after super() 
7

धन्यवाद:

class FooBase(object): 
    def foo(self): 
     print 'FooBase.foo()' 

class A(FooBase): 
    def foo(self): 
     print 'A.foo() before super()' 
     super(A, self).foo() 
     print 'A.foo() after super()' 

class B(FooBase): 
    def foo(self): 
     print 'B.foo() before super()' 
     super(B, self).foo() 
     print 'B.foo() after super()' 

class C(A, B): 
    def foo(self): 
     print 'C.foo() before super()' 
     super(C, self).foo() 
     print 'C.foo() after super()' 

यह बाहर प्रिंट होगा। संक्षेप में:

  • The (currently) accepted answer गलत है। सही वर्णन होना चाहिए: सुपर() एकल विरासत को हल करने के लिए केवल अच्छा नहीं है, बल्कि कई विरासत भी है।

    स्पष्ट रूप से आधार वर्ग तरीकों बुला प्रश्नकर्ता के उदाहरण की तरह बहुत ही सरल परिदृश्यों के लिए काम कर सकते हैं, वहीं यह टूट जाएगा अगर आधार वर्ग खुद को एक आम से विरासत: और कारण अच्छी तरह से @blckknght की टिप्पणी से समझाया गया है आधार और आप अंतिम आधार वर्ग की विधि को दो बार नहीं बुला सकते हैं। इसे "हीरा विरासत" के रूप में जाना जाता है और यह कई एकाधिक विरासत प्रणालियों (जैसे सी ++ में) के लिए एक बड़ी समस्या है। पायथन की सहयोगी एकाधिक विरासत (सुपर() के साथ) आपको कई मामलों में आसानी से हल करने देता है (हालांकि यह कहना नहीं है कि एक सहकारी एकाधिक विरासत पदानुक्रम डिजाइन करना आसान है या हमेशा एक अच्छा विचार है)।

  • उचित तरीका, @duncan pointed out के रूप में, सुपर() का उपयोग करना है, लेकिन इसे लगातार उपयोग करें।

    super वास्तव में इस स्थिति के लिए है, लेकिन यह केवल तभी काम करता है जब आप लगातार इसका उपयोग करते हैं। यदि आधार वर्ग super का भी उपयोग नहीं करते हैं, तो यह काम नहीं करेगा, और जब तक कि विधि object में न हो, आपको super कॉल की श्रृंखला को समाप्त करने के लिए सामान्य बेस क्लास की तरह कुछ उपयोग करना होगा।

    class FooBase(object): 
        def foo(self): pass 
    
    class A(FooBase): 
        def foo(self): 
         super(A, self).foo() 
         print 'A.foo()' 
    
    class B(FooBase): 
        def foo(self): 
         super(B, self).foo() 
         print 'B.foo()' 
    
    class C(A, B): 
        def foo(self): 
         super(C, self).foo() 
         print 'C.foo()' 
    
    C().foo() # Run this 
    

    लेकिन यह भी कहना है कि, विधि बुला आदेश लगते सहज नहीं हो सकता है लायक है। नतीजा यह है:

    B.foo() 
    A.foo() 
    C.foo() 
    

    और इस प्रतीत होता है कि यह अजीब आदेश एमआरओ पर आधारित है। As @Manoj-Govindan pointed out,

    super() "पहली" सुपर क्लास पर foo विधि को कॉल करेगा। यह C वर्ग के लिए विधि समाधान आदेश (__mro__) पर आधारित है।

    >>> C.__mro__ 
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>) 
    >>> 
    
  • एक सामान्य नियम के रूप में, आप वापस सभी माता-पिता के तरीकों के लिए यात्रा करना चाहते हैं, लेकिन वास्तव में आह्वान आदेश की परवाह नहीं करते, consisently super() का उपयोग करें। अन्यथा, आप एक विशिष्ट क्रम में स्पष्ट रूप से पैरेंट विधियों को कॉल करना चुन सकते हैं।

  • हालांकि सुपर() और स्पष्ट कॉलिंग के उपयोग को मिश्रित न करें। अन्यथा आप this answer में उल्लिखित ग़लत नकल को समाप्त कर देंगे।

पीएस: मैंने ऊपर वर्णित अधिकांश स्रोतों को ऊपर उठाया है।

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