क्या पायथन में किसी अन्य वर्ग के अंदर एक वर्ग को परिभाषित करने का कोई लाभ है?


106

मैं यहाँ जो बात कर रहा हूँ वह नेस्टेड क्लासेस हैं। अनिवार्य रूप से, मेरे पास दो कक्षाएं हैं जो मैं मॉडलिंग कर रहा हूं। एक DownloadManager वर्ग और एक DownloadThread वर्ग। यहाँ स्पष्ट OOP अवधारणा रचना है। हालांकि, रचना जरूरी नहीं कि घोंसले के शिकार, सही है?

मेरे पास कोड है जो कुछ इस तरह दिखता है:

class DownloadThread:
    def foo(self):
        pass

class DownloadManager():
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadThread())

लेकिन अब मैं सोच रहा हूं कि क्या ऐसी स्थिति होगी जहां घोंसला बनाना बेहतर होगा। कुछ इस तरह:

class DownloadManager():
    class DownloadThread:
        def foo(self):
            pass
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadManager.DownloadThread())

जवाबों:


122

आप ऐसा तब करना चाह सकते हैं जब "इनर" क्लास वन-ऑफ़ हो, जिसका उपयोग बाहरी क्लास की परिभाषा के बाहर कभी नहीं किया जाएगा । उदाहरण के लिए मेटाक्लास का उपयोग करना, यह कभी-कभी करना आसान होता है

class Foo(object):
    class __metaclass__(type):
        .... 

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

केवल दूसरी बार जब मैंने इस तरह से नेस्टेड कक्षाओं का उपयोग किया है, तो मैंने बाहरी वर्ग का उपयोग केवल नाम मात्र के रूप में किया है ताकि निकटवर्ती कक्षाओं का एक समूह बना सकें:

class Group(object):
    class cls1(object):
       ...

    class cls2(object):
       ...

फिर दूसरे मॉड्यूल से, आप समूह को आयात कर सकते हैं और इन्हें Group.cls1, Group.cls2 आदि के रूप में संदर्भित कर सकते हैं, हालांकि कोई यह तर्क दे सकता है कि आप मॉड्यूल का उपयोग करके बिल्कुल (शायद कम भ्रमित तरीके से) समान रूप से पूरा कर सकते हैं।


13
I -would- का तर्क है कि दूसरे मामले में, आप निश्चित रूप से-एक मॉड्यूल या पैकेज का उपयोग करके बेहतर सेवा करेंगे, जो नामस्थान के लिए डिज़ाइन किए गए हैं।
मैथ्यू ट्रेवर

5
यह एक शानदार जवाब है। सरल, टू द पॉइंट, और मॉड्यूल का उपयोग करने की वैकल्पिक विधि का उल्लेख करता है। +1
कॉर्नस्मिथ

5
सिर्फ रिकॉर्ड के लिए, उन लोगों के लिए जो हठवादितापूर्ण पैकेज और उचित मॉड्यूल में अपने कोड को व्यवस्थित करने से इनकार कर सकते हैं या नहीं कर सकते हैं, कई बार नाम स्थान के रूप में कक्षाओं का उपयोग करना किसी भी चीज का उपयोग न करने से बेहतर हो सकता है।
एक्यूमेनस

19

मैं अजगर को नहीं जानता, लेकिन आपका सवाल बहुत सामान्य है। अगर यह पायथन के लिए विशिष्ट है तो मुझे अनदेखा करें।

वर्ग घोंसला बनाना सभी गुंजाइश है। यदि आपको लगता है कि एक वर्ग केवल दूसरे के संदर्भ में समझ में आएगा, तो पूर्व शायद एक नेस्टेड वर्ग बनने के लिए एक अच्छा उम्मीदवार है।

यह एक सामान्य पैटर्न है जो हेल्पर वर्गों को निजी, नेस्टेड कक्षाओं के रूप में बनाता है।


9
सिर्फ रिकॉर्ड के लिए ध्यान दें, privateकक्षाओं की अवधारणा पायथन में इतनी लागू नहीं होती है, लेकिन एक निहित उपयोग गुंजाइश अभी भी निश्चित रूप से लागू होती है।
एक्यूमेनस

7

नेस्टेड क्लास के लिए एक और उपयोग है, जब कोई विरासत में मिली कक्षाओं का निर्माण करना चाहता है जिनकी बढ़ी हुई कार्यक्षमता एक विशिष्ट नेस्टेड वर्ग में एनकैप्सुलेटेड होती है।

इस उदाहरण को देखें:

class foo:

  class bar:
    ...  # functionalities of a specific sub-feature of foo

  def __init__(self):
    self.a = self.bar()
    ...

  ...  # other features of foo


class foo2(foo):

  class bar(foo.bar):
    ... # enhanced functionalities for this specific feature

  def __init__(self):
    foo.__init__(self)

ध्यान दें कि के कंस्ट्रक्टर में foo, लाइन self.a = self.bar()का निर्माण foo.barतब होगा जब निर्माण की जा रही वस्तु वास्तव में एक fooऑब्जेक्ट है, और foo2.barजब ऑब्जेक्ट का निर्माण किया जा रहा है तो वास्तव में एक foo2ऑब्जेक्ट है।

यदि वर्ग barको वर्ग के fooबजाय परिभाषित किया गया था , साथ ही इसके विरासत वाले संस्करण (जिसे bar2उदाहरण के लिए कहा जाएगा ), तो नई कक्षा foo2को परिभाषित करना बहुत अधिक दर्दनाक होगा, क्योंकि कब्जाने वाले foo2को इसकी पहली पंक्ति को प्रतिस्थापित करने की आवश्यकता होगी self.a = bar2(), जिसका तात्पर्य है पूरे रचनाकार को फिर से लिखना।


6

ऐसा करने का वास्तव में कोई लाभ नहीं है, सिवाय इसके कि अगर आप मेटाक्लासेस के साथ काम कर रहे हैं।

वर्ग: सुइट वास्तव में वह नहीं है जो आपको लगता है कि यह है। यह एक अजीब गुंजाइश है, और यह अजीब चीजें करता है। यह वास्तव में एक वर्ग भी नहीं बनाता है! यह कुछ चर को इकट्ठा करने का एक तरीका है - वर्ग का नाम, आधार, विशेषताओं का एक छोटा शब्दकोश और एक मेटाक्लस।

नाम, शब्दकोश और ठिकानों को सभी उस फ़ंक्शन को पास कर दिया जाता है जो मेटाक्लास है, और फिर इसे उस क्षेत्र में चर 'नाम' को सौंपा गया है जहां वर्ग: सूट था।

आप मेटाक्लासेस के साथ खिलवाड़ करके क्या हासिल कर सकते हैं, और वास्तव में आपके स्टॉक स्टैण्डर्ड क्लासेस के भीतर नेस्टिंग क्लासेस के लिए, कोड को पढ़ना मुश्किल है, कोड को समझना कठिन है, और विषम त्रुटियां जिन्हें समझना बेहद मुश्किल है, क्योंकि वे 'क्लास' से परिचित नहीं हैं। गुंजाइश पूरी तरह से किसी भी अन्य अजगर गुंजाइश के लिए अलग है।


3
असहमत: अपवाद वर्गों को घोंसला बनाना बहुत उपयोगी है, क्योंकि आपकी कक्षा के उपयोगकर्ता बिना किसी गड़बड़ आयात के आपके कस्टम अपवादों की जांच कर सकते हैं। जैसेexcept myInstanceObj.CustomError, e:
रोबम

2
@ जेरूब, वह बुरा क्यों है?
राबर्ट सीमर

5

आप वर्ग जनरेटर के रूप में एक वर्ग का उपयोग कर सकते हैं। जैसे और कफ कोड से कुछ में :)

class gen(object):
    class base_1(object): pass
    ...
    class base_n(object): pass

    def __init__(self, ...):
        ...
    def mk_cls(self, ..., type):
        '''makes a class based on the type passed in, the current state of
           the class, and the other inputs to the method'''

मुझे लगता है कि जब आपको इस कार्यक्षमता की आवश्यकता होगी तो यह आपके लिए बहुत स्पष्ट होगा। यदि आपको इसके समान कुछ करने की आवश्यकता नहीं है तो शायद यह एक अच्छा उपयोग मामला नहीं है।


1

नहीं, रचना का अर्थ घोंसला बनाना नहीं है। यदि आप इसे बाहरी वर्ग के नाम स्थान में अधिक छिपाना चाहते हैं, तो एक नेस्टेड वर्ग होने का कोई मतलब नहीं होगा।

वैसे भी, मुझे आपके मामले में नेस्टिंग के लिए कोई व्यावहारिक उपयोग नहीं दिखता है। यह कोड को पढ़ने (समझने) के लिए कठिन बना देगा और यह इंडेंटेशन को भी बढ़ाएगा जो लाइनों को कम और विभाजन के लिए अधिक प्रवण बना देगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.