2011-01-25 16 views
5

Abstract base classes can still be handy in Python. एक सार आधार वर्ग जहां मैं हर उपवर्ग है, कहते हैं चाहते हैं, एक spam() विधि लेखन में, मैं कुछ इस तरह लिखना चाहते हैं चुनौती super() का उपयोग करने और उप-वर्गों की पूरी श्रृंखला में इसे शामिल करके ठीक से करने के लिए भी आती है। इस मामले में, ऐसा लगता है मैं हर super कॉल की तरह लपेट के लिए निम्नलिखित:पायथन के सुपर(), सार आधार वर्ग, और NotImplementedError

class Useful(Abstract): 
    def spam(self): 
     try: 
      super(Useful, self).spam() 
     except NotImplementedError, e: 
      pass 
     print("It's okay.") 

यह एक सरल उपवर्ग के लिए ठीक है, लेकिन जब एक वर्ग के कई तरीके है कि लेखन, कोशिश को छोड़कर बात थोड़ा बोझिल हो जाता है , और थोड़ा बदसूरत। क्या सार आधार वर्गों से उप-वर्गीकरण का एक और शानदार तरीका है? क्या मैं बस गलत कर रहा हूँ?

+5

बहुत कम समझ में आता है कि। आपको पता होना चाहिए कि कौन सा सुपरक्लास विधियां लागू की गई हैं (जिसके लिए 'सुपर' समझ में आता है) और जिन्हें लागू नहीं किया गया है क्योंकि वे सार हैं। आप स्रोत पढ़ सकते हैं। –

+0

'सिंटेक्स एरर' उठाएं भाषा में भी है। सवाल यह है कि "उस कोड को क्यों लिखें जब अमूर्त वर्ग का सरल निरीक्षण आपको उस कोड को लिखने से बचा सकता है"? –

+0

@ एसएलओटी आह, अब समझ में आया। आपको इसे उत्तर के रूप में प्रस्तुत करना चाहिए, क्योंकि यह है। – gotgenes

उत्तर

8

आप abc module साथ अजगर 2.6+ में सफाई से यह कर सकते हैं:

import abc 
class B(object): 
    __metaclass__ = abc.ABCMeta 
    @abc.abstractmethod 
    def foo(self): 
     print 'In B' 

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

C().foo() 

व्यवहृत किया जा सकेगा

In B 
In C 
+0

यह जरूरी नहीं है - कोई आपके उदाहरण से बी को तत्काल नहीं कर सकता है। –

+0

दिलचस्प! मैंने 'एबीसी' मॉड्यूल के अलावा भी पकड़ा नहीं था! – gotgenes

+0

@Tomasz भी दिलचस्प है। यूनिट परीक्षण के लिए क्या प्रभाव हैं, फिर, यदि कोई कक्षा को तुरंत चालू नहीं कर सकता है? – gotgenes

7

कि सभी कोड लिखने है। अमूर्त वर्ग का सरल निरीक्षण आपको उस कोड को लिखने से बचा सकता है।

यदि विधि सार है, तो ठोस उपclass सुपर को कॉल नहीं करता है।

यदि विधि ठोस है, तो कंक्रीट सबक्लास सुपर कॉल करता है।

+1

यह एक साधारण समाधान है जब तक कि आप एक अलग तरह के सहकारी विरासत के लिए नहीं जा रहे हैं। अर्थात। सार ए ए - बी है, लेकिन फिर आप सी के सम्मिलन का समर्थन करना चाहते हैं जैसे ए <- सी <- बी बी सुपर को कॉल नहीं करता है, इसलिए यह ठीक से काम नहीं करता है। मुझे लगता है कि मुख्य बिंदु यह है कि जब आप सुपर का उपयोग करते हैं तो आपको सहकारी विरासत और अपने विशिष्ट वर्ग पदानुक्रम के लिए अपने लक्ष्यों से अवगत होना चाहिए। उपरोक्त मेरे उदाहरण के कार्यान्वयन के लिए मेरा जवाब देखें। –

3

यह समझने का मुख्य बिंदु super() सहकारी विरासत को लागू करने के लिए है। कक्षाएं सहयोग कैसे आपके लिए प्रोग्रामर है। super() जादू नहीं है और आप जो चाहते हैं उसे बिल्कुल नहीं पता! एक फ्लैट पदानुक्रम के लिए सुपर का उपयोग करने में बहुत कुछ नहीं है जिसे सहकारी विरासत की आवश्यकता नहीं है, इसलिए उस मामले में एस लॉट का सुझाव स्पॉट पर है। उपयोगी मई के उपवर्गों या अपने लक्ष्यों को :)

उदाहरण के लिए निर्भर करता है super() उपयोग नहीं करना चाहते हो सकता है: - बी, लेकिन फिर आप की तरह तो एक < सी की प्रविष्टि का समर्थन करना चाहते - सार उ < है सी < - बी ।

class A(object):                       
    """I am an abstract abstraction :)""" 
    def foo(self): 
     raise NotImplementedError('I need to be implemented!') 

class B(A): 
    """I want to implement A""" 
    def foo(self): 
     print('B: foo') 
     # MRO Stops here, unless super is not A 
     position = self.__class__.__mro__.index 
     if not position(B) + 1 == position(A): 
      super().foo() 

b = B()  
b.foo() 

class C(A): 
    """I want to modify B and all its siblings (see below)""" 
    def foo(self): 
     print('C: foo') 
     # MRO Stops here, unless super is not A 
     position = self.__class__.__mro__.index 
     if not position(C) + 1 == position(A): 
      super().foo() 

print('') 
print('B: Old __base__ and __mro__:\n') 
print('Base:', B.__bases__) 
print('MRO:', B.__mro__) 
print('') 
# __mro__ change implementation 
B.__bases__ = (C,) 
print('B: New __base__ and __mro__:\n') 
print('Base:', B.__bases__) 
print('MRO:', B.__mro__) 
print('') 
b.foo() 

और उत्पादन:

B: foo 

B: Old __base__ and __mro__: 

Base: (<class '__main__.A'>,) 
MRO: (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>) 

B: New __base__ and __mro__: 

Base: (<class '__main__.C'>,) 
MRO: (<class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) 

B: foo 
C: foo