2011-06-18 19 views
13

इस पर कोई अच्छा ऑनलाइन प्रलेखन प्रतीत नहीं होता है: यदि मैं व्युत्पन्न कक्षा बना देता हूं, तो क्या यह स्वचालित रूप से बेस क्लास के सभी गुण होंगे? लेकिन BaseClass.__init() के लिए क्या है, क्या आपको इसे अन्य बेस क्लास तरीकों से करने की भी आवश्यकता है? BaseClass.__init__() तर्क की आवश्यकता है? यदि आपके बेस क्लास __init__() के लिए तर्क हैं, तो क्या वे व्युत्पन्न कक्षा द्वारा भी उपयोग किए जाते हैं, क्या आपको व्युत्पन्न क्लैस के __init__() पर तर्कों को स्पष्ट रूप से सेट करने की आवश्यकता है, या उन्हें BaseClass.__init__() पर सेट करें?पायथन ने क्लास और बेस क्लास विशेषताओं को व्युत्पन्न किया?

उत्तर

9

If I make a derived class, will it automatically have all the attributes of the base class?

कक्षा विशेषताएँ, हाँ। इंस्टेंस विशेषताएँ, नहीं (केवल इसलिए कि जब वर्ग बनाया जाता है तो वे मौजूद नहीं होते हैं), जब तक व्युत्पन्न कक्षा में __init__ नहीं होता है, उस स्थिति में बेस बेस को इसके बजाय कॉल किया जाएगा, और इंस्टेंस विशेषताओं को सेट करेगा।

Does BaseClass.init() need arguments?

कक्षा और उसके __init__ हस्ताक्षर पर निर्भर करता है। यदि आप व्युत्पन्न कक्षा में Base.__init__ को स्पष्ट रूप से कॉल कर रहे हैं, तो आपको कम से कम self को पहले तर्क के रूप में पास करने की आवश्यकता होगी। आप

class Base(object): 
    def __init__(self): 
     # something 

है तो यह नहीं बल्कि स्पष्ट है कि कोई अन्य तर्कों __init__ द्वारा स्वीकार कर रहे हैं। आप

class Base(object): 
    def __init__(self, argument): 
     # something 

होगा तो आप जब आधार __init__ बुला argument पारित करने के लिए की है। यहां कोई रॉकेट विज्ञान नहीं है।

If you have arguments for your base class init(), are they also used by the derived class, do you need to explicitly set the arguments to the derived classe's init(), or set them to BaseClass.init() instead?

फिर, अगर व्युत्पन्न वर्ग __init__ नहीं है, आधार एक स्थान पर किया जाएगा।

class Base(object): 
    def __init__(self, foo): 
     print 'Base' 

class Derived(Base): 
    pass 

Derived() # TypeError 
Derived(42) # prints Base 

अन्य मामले में, आपको किसी भी तरह इसका ख्याल रखना होगा। चाहे आप *args, **kwargs का उपयोग करें और केवल बेस क्लास को अनमोडिफाइड तर्क दें, या बेस क्लास हस्ताक्षर की प्रतिलिपि बनाएँ, या अन्यत्र से तर्क प्रदान करें, जो आप पूरा करने की कोशिश कर रहे हैं उस पर निर्भर करता है।

43

आप एक वर्ग BaseClass से व्युत्पन्न में __init__ लागू है, तो यह विरासत में मिला __init__ विधि के ऊपर लिख देगा और इतने BaseClass.__init__ कहा जा कभी नहीं होगा। यदि आपको बेस क्लास (जैसा आमतौर पर मामला है) के लिए __init__ विधि को कॉल करने की आवश्यकता है, तो यह करने के लिए आप पर निर्भर है, और यह BaseClass.__init__ पर कॉल करके स्पष्ट रूप से किया गया है, आमतौर पर नए लागू __init__ विधि के भीतर से।

class Foo(object): 
    def __init__(self): 
     self.a = 10 

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     self.b = 20 

bar = Bar() 
bar.do_something() 

यह निम्न त्रुटि के कारण होगा:

AttributeError: 'Bar' object has no attribute 'a' 

तो, do_something विधि के रूप में उम्मीद विरासत में मिला दिया गया है, लेकिन यह है कि विधि विशेषता a करने के लिए सेट किया गया है, जो इसे कभी नहीं क्योंकि __init__ है की आवश्यकता है भी अधिलेखित किया गया था। Bar.__init__ के भीतर से हम Foo.__init__ को स्पष्ट रूप से कॉल करके इसे गोल करते हैं।

class Foo(object): 
    def __init__(self): 
     self.a = 10 

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     Foo.__init__(self) 
     self.b = 20 

bar = Bar() 
bar.do_something() 

जो 10 प्रिंट करता है जैसा कि प्रिंट करता है।इस मामले में Foo.__init__ एक एकल तर्क की अपेक्षा करता है जो Foo का उदाहरण है (जिसे सम्मेलन द्वारा self कहा जाता है)।

आम तौर पर, जब आप किसी वर्ग के उदाहरण पर कोई विधि कॉल करते हैं, तो क्लास इंस्टेंस स्वचालित रूप से पहले तर्क के रूप में पारित हो जाता है। किसी वर्ग के उदाहरण पर विधियों को बाध्य विधियों कहा जाता है। bar.do_something एक बाध्य विधि का एक उदाहरण है (और आप ध्यान दें कि इसे बिना किसी तर्क के कहा जाता है)। Foo.__init__ एक अनबाउंड विधि है क्योंकि यह Foo के किसी विशेष उदाहरण से जुड़ा हुआ नहीं है, इसलिए पहला तर्क, Foo का एक उदाहरण स्पष्ट रूप से पारित करने की आवश्यकता है।

हमारे मामले में, हम Foo.__init__ को self गुजरती हैं, जो Bar का उदाहरण है कि Bar में __init__ विधि करने के लिए पारित किया गया था है। चूंकि BarFoo से विरासत प्राप्त करता है, Bar के उदाहरण भी Foo के उदाहरण हैं, इसलिए self से Foo.__init__ पर जाने की अनुमति है।

यह संभावना है कि जिस वर्ग से आप विरासत में हैं, वह कक्षा के एक उदाहरण की तुलना में अधिक तर्कों को स्वीकार या स्वीकार करता है।

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

    def do_something(self): 
     print self.a 

class Bar(Foo): 
    def __init__(self): 
     Foo.__init__(self, 20) 

bar = Bar() 
bar.do_something() 

जो 20 प्रिंट होगा: इन के रूप में आप कोई भी तरीका आप __init__ के भीतर से कॉल कर रहे हैं के साथ होता है के साथ पेश कर रहे हैं।

यदि आप एक इंटरफ़ेस को कार्यान्वित करने का प्रयास कर रहे हैं जो आपकी विरासत कक्षा के माध्यम से बेस क्लास के सभी प्रारंभिक तर्कों को पूरी तरह से उजागर करता है, तो आपको स्पष्ट रूप से ऐसा करने की आवश्यकता होगी। यह आम तौर पर * तर्क और ** kwargs तर्क (नाम सम्मेलन द्वारा होते हैं) के साथ किया जाता है, जो सभी शेष तर्कों के लिए प्लेसहोल्डर हैं जिन्हें स्पष्ट रूप से नामित नहीं किया गया है। इस मामले में

class Foo(object): 
    def __init__(self, a, b=10): 
     self.num = a * b 

    def do_something(self): 
     print self.num 

class Bar(Foo): 
    def __init__(self, c=20, *args, **kwargs): 
     Foo.__init__(self, *args, **kwargs) 
     self.c = c 

    def do_something(self): 
     Foo.do_something(self) 
     print self.c 


bar = Bar(40, a=15) 
bar.do_something() 

, तर्क c, 40 होने के लिए सेट कर दिया जाता है क्योंकि यह Bar.__init__ को पहला तर्क है: निम्न उदाहरण मैं चर्चा की है सब कुछ का उपयोग करता है। दूसरा तर्क तब चर के args और kwargs (* और ** विशिष्ट वाक्यविन्यास है जो कहता है कि फ़ंक्शन/विधि को पार करते समय सूची/ट्यूपल या शब्दकोश को अलग-अलग तर्कों में विस्तारित करता है) में 0xपर भेजा जाता है।

यह उदाहरण यह भी इंगित करता है कि किसी भी अधिलेखित विधि को स्पष्ट रूप से कॉल करने की आवश्यकता है यदि आवश्यक है (do_something इस मामले में है)।

एक अंतिम बिंदु, आप अक्सर super(ChildClass, self).method() देखेंगे (जहां ChildClass कुछ मनमाने ढंग से बच्चे वर्ग है) BaseClass विधि स्पष्ट रूप से करने के लिए एक फोन के बजाय प्रयोग किया जा रहा। super की चर्चा एक अन्य प्रश्न है, लेकिन यह कहने के लिए पर्याप्त है, इन मामलों में आमतौर पर इसका इस्तेमाल BaseClass.method(self) पर कॉल करके किया जा रहा है। संक्षेप में, super विधि समाधान आदेश में अगली कक्षा में विधि कॉल का प्रतिनिधित्व करता है - एमआरओ (जो एकल विरासत में मूल वर्ग है)। अधिक जानकारी के लिए documentation on super देखें।

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