2012-07-24 21 views
7

पायथन कक्षाओं में सार्वजनिक/निजी की कोई अवधारणा नहीं है, इसलिए हमें कुछ ऐसा स्पर्श नहीं करने के लिए कहा जाता है जो अंडरस्कोर से शुरू होता है जब तक कि हम इसे नहीं बनाते। लेकिन क्या हमें उन सभी वर्गों के पूर्ण ज्ञान की आवश्यकता नहीं है, जिनसे हम प्रत्यक्ष या परोक्ष रूप से उत्तराधिकारी हैं? गवाह:क्या पाइथन को विरासत श्रृंखला में सभी वर्गों के अंतरंग ज्ञान की आवश्यकता है?

class Base(object): 
    def __init__(self): 
     super(Base, self).__init__() 
     self._foo = 0 

    def foo(self): 
     return self._foo + 1 

class Sub(Base): 
    def __init__(self): 
     super(Sub, self).__init__() 
     self._foo = None 

Sub().foo() 

उम्मीद के मुताबिक, एक TypeError जब None + 1 मूल्यांकन किया जाता है उठाया है। तो मुझे पता होना चाहिए कि _foo बेस क्लास में मौजूद है। इसके आस-पास पहुंचने के लिए, __foo का उपयोग इसके बजाय किया जा सकता है, जो नाम को उलझाने में समस्या हल करता है। ऐसा लगता है, अगर सुरुचिपूर्ण नहीं है, तो एक स्वीकार्य समाधान। हालांकि, Base किसी वर्ग (एक अलग पैकेज में) से Sub नामक विरासत में क्या होता है? Sub में __foo दादा Sub में __foo ओवरराइड __foo

इसका तात्पर्य है कि मुझे प्रत्येक विरासत श्रृंखला को जानना होगा, जिसमें प्रत्येक "निजी" ऑब्जेक्ट्स शामिल हैं। तथ्य यह है कि पाइथन गतिशील रूप से टाइप किया गया है, यह भी कठिन बनाता है, क्योंकि खोज के लिए कोई घोषणा नहीं है। सबसे बुरा हिस्सा, हालांकि, शायद Baseobject से प्राप्त हो सकता है, लेकिन भविष्य में रिलीज में, यह Sub से विरासत में बदल जाता है। स्पष्ट रूप से अगर मुझे पता है कि Sub विरासत में मिला है, तो मैं अपनी कक्षा का नाम बदल सकता हूं, हालांकि यह परेशान है। लेकिन मैं भविष्य में नहीं देख सकता।

क्या यह ऐसा कोई मामला नहीं है जहां एक वास्तविक निजी डेटा प्रकार किसी समस्या को रोक देगा? कैसे, पायथन में, क्या मैं यह सुनिश्चित कर सकता हूं कि मैं किसी के पैर की उंगलियों पर गलती से कदम नहीं उठा रहा हूं यदि भविष्य में किसी भी बिंदु पर उन पैर की उंगलियों का अस्तित्व हो सकता है?

संपादित: मैं जाहिरा तौर पर स्पष्ट प्राथमिक सवाल नहीं किए हैं। मैं नाम मैंगलिंग और एक सिंगल और डबल अंडरस्कोर के बीच का अंतर से परिचित हूं। सवाल यह है कि मैं इस तथ्य से कैसे निपट सकता हूं कि मैं कक्षाओं के साथ संघर्ष कर सकता हूं जिसका अस्तित्व मुझे अभी के बारे में नहीं पता है? अगर मेरे माता-पिता वर्ग (जो पैकेज में मैंने लिखा नहीं है) एक वर्ग से विरासत शुरू करने के लिए होता है, जो मेरी कक्षा के समान नाम से होता है, यहां तक ​​कि नाम मैंगलिंग भी मदद नहीं करेगा। क्या मैं इसे (कोने) मामले के रूप में देखने में गलत हूं कि सच्चे निजी सदस्य हल करेंगे, लेकिन पाइथन को परेशानी है?

संपादित:

फ़ाइल parent.py:

class Sub(object): 
    def __init__(self): 
     self.__foo = 12 
    def foo(self): 
     return self.__foo + 1 
class Base(Sub): 
    pass 

फ़ाइल sub.py: अनुरोध अनुसार, निम्नलिखित एक पूर्ण उदाहरण है

import parent 
class Sub(parent.Base): 
    def __init__(self): 
     super(Sub, self).__init__() 
     self.__foo = None 
Sub().foo() 

दादा-दादी के foo कहा जाता है, लेकिन मेरे __foo का उपयोग किया जाता है।

जाहिर है आप इस तरह अपने आप को कोड लिखने नहीं होगा, लेकिन parent आसानी से तीसरे पक्ष द्वारा प्रदान किया जा सकता है, जो के विवरण किसी भी समय बदल सकता है।

+0

आपको एक उदाहरण पोस्ट इस जहां अन्य एक ही नामित वर्ग does not को पूरी तरह से अपने मौजूदा कक्षा शैडो प्रदर्शित करने के लिए कर सकते हैं? .. या शायद मैं अभी भी understanding..nevermind नहीं ... मैं एक बना दिया है और अपने अधिकार मैं लगता है कि यह एक कोने है मामला ... बस सामान्य निजी var/वर्ग नामों का उपयोग न करने का प्रयास करें, मुझे लगता है कि –

उत्तर

2

इसका तात्पर्य है कि मुझे पूरी विरासत श्रृंखला जाननी है। । ।

हां, आपको पूरी विरासत श्रृंखला, या उस ऑब्जेक्ट के दस्तावेज़ों को जानना चाहिए जो आप सीधे उप-वर्गीकरण कर रहे हैं, आपको यह बताना चाहिए कि आपको क्या जानना है।

उपclassing एक उन्नत सुविधा है, और देखभाल के साथ इलाज किया जाना चाहिए।

को निर्दिष्ट क्या एक उपवर्ग में अधिरोहित किया जाना चाहिए डॉक्स का एक अच्छा उदाहरण threading class है:

इस वर्ग के एक गतिविधि है कि नियंत्रण से एक अलग थ्रेड में चलाया जाता है प्रतिनिधित्व करता है। गतिविधि निर्दिष्ट करने के दो तरीके हैं: कन्स्ट्रक्टर को कॉल करने योग्य ऑब्जेक्ट पास करके, या उप-वर्ग में run() विधि को ओवरराइड करके। किसी अन्य विधि (कन्स्ट्रक्टर को छोड़कर) को सबक्लास में ओवरराइड किया जाना चाहिए। दूसरे शब्दों में, केवल इस वर्ग के __init__() और run() विधियों को ओवरराइड करें।

7

उपयोग private names (बजाय संरक्षित वाले), एक डबल अंडरस्कोर के साथ शुरू:

class Sub(Base): 
    def __init__(self): 
     super(Sub, self).__init__() 
     self.__foo = None 
     # ^^ 

Base में _foo या __foo के साथ संघर्ष नहीं होगा।ऐसा इसलिए है क्योंकि पायथन डबल अंडरस्कोर को एक अंडरस्कोर और कक्षा के नाम से बदल देता है; निम्नांकित दो पंक्तियों के बराबर हैं:

class Sub(Base): 
    def x(self): 
     self.__foo = None # .. is the same as .. 
     self._Sub__foo = None 

(संपादित करने के लिए :) मौका है कि एक वर्ग पदानुक्रम में दो वर्गों केवल एक ही नाम नहीं है, लेकिन वे दोनों एक ही प्रॉपर्टी का नाम प्रयोग कर रहे हैं कि, और जवाब में निजी मैंगलेड (__) दोनों का उपयोग कर रहे हैं, यह बहुत कम है कि इसे अभ्यास में सुरक्षित रूप से अनदेखा किया जा सकता है (मैंने किसी एक के लिए अभी तक एक मामले के बारे में नहीं सुना है)।

सिद्धांत रूप में, हालांकि, आप औपचारिक रूप से किसी प्रोग्राम की शुद्धता को सत्यापित करने के लिए सही हैं, सबसे अधिक संपूर्ण विरासत श्रृंखला को जानते हैं। सौभाग्य से, औपचारिक सत्यापन के लिए आमतौर पर किसी भी मामले में पुस्तकालयों के एक निश्चित सेट की आवश्यकता होती है।

यह Zen of Python की भावना, जिसमें शामिल है

व्यावहारिकता शुद्धता धड़कता है। तो अपने Base.__foo और Sub.__foo अलग-अलग नाम होगा

+0

लेकिन क्या यह एक काल्पनिक 'बेस .__ foo' के साथ संघर्ष करेगा? – inspectorG4dget

+0

@ इंस्पेक्टर जी 4 डीजेट नोप। – phihag

+0

मुझे लगता है कि यह आपके उत्तर में विशेष उल्लेख के लायक है क्योंकि यह ओपी प्रतीत होता है कि ओपी क्या लगता है कि ओपी लगता है कि – inspectorG4dget

3
  1. नाम mangling वर्ग भी शामिल है। नाम मैंगलिंग सुविधा को पायथन पर पहली जगह जोड़ने का यही कारण था। एक _Base__foo होगा, अन्य _Sub__foo

  2. कई लोग इन कारणों में से कुछ के लिए विरासत (है-ए) की बजाय संरचना (है-ए) का उपयोग करना पसंद करते हैं।

+0

यह गलत नहीं है? मैंने सोचा कि केवल डबल अंडरस्कोर के साथ उलझन में नहीं है ... –

+0

मैंने नाम उलझन का उल्लेख किया; मैंने देखा विशेष मामला ए-> बी-> ए जैसे कुछ था (जहां पहला ए स्पष्ट रूप से एक अलग पैकेज में है)। अब दादाजी वर्ग चीजों को मैग्लिंग करता है वैसे ही मेरा सबक्लास करता है, जो लाभ का नाम है जो मैंगलिंग प्रदान करता है। – Chris

+0

@ जोरन बेस्ले: मैं डबल अंडरस्कोर का उपयोग कर रहा हूं ... –

0

के रूप में बताया गया है, आप नाम mangling उपयोग कर सकते हैं। हालांकि, यदि आप अपना कोड पर्याप्त रूप से दस्तावेज करते हैं तो आप एक अंडरस्कोर (या कोई नहीं!) के साथ रह सकते हैं - आपके पास इतने सारे निजी चर नहीं होना चाहिए कि यह एक समस्या साबित हो। बस यह कहें कि क्या कोई विधि किसी निजी चर पर निर्भर करती है, और उपयोगकर्ताओं को चेतावनी देने के लिए या तो वेरिएबल, या क्लास डॉकस्ट्रिंग में विधि का नाम जोड़ती है।

आगे, यदि आप यूनिट परीक्षण बनाते हैं, तो आपको उन परीक्षणों को बनाना चाहिए जो सदस्यों पर आविष्कार की जांच करते हैं, और तदनुसार ये ऐसे नाम संघर्ष दिखा सकते हैं।

तुम सच में "निजी" चर है, और जो भी कारण नाम-mangling अपनी जरूरतों को पूरा नहीं करता है, तो आप एक और वस्तु में अपने निजी राज्य कारक बन सकते हैं के लिए करना चाहते हैं:

class Foo(object): 

    class Stateholder(object): pass 

    def __init__(self): 
     self._state = Stateholder() 
     self.state.private = 1 
+0

इस प्रकार निहितार्थ यह है कि एक बार जब आप कक्षा लिखते हैं, तो आप इसे कभी भी संशोधित नहीं कर सकते कि यह कैसे काम करता है, क्योंकि इससे प्राप्त होने वाले किसी भी व्यक्ति ने आपके नाम का उपयोग किया हो सकता है संशोधनों? यदि लक्षण का इलाज करने का कोई वास्तविक तरीका नहीं है, तो यूनिट परीक्षण लक्षण का इलाज करने का सबसे अच्छा तरीका हो सकता है। – Chris

+0

@Chris आप जिस समस्या की कल्पना करते हैं वह उस रूप में मौजूद नहीं है जिसकी आप कल्पना कर रहे हैं। यदि आप एक नया सार्वजनिक नाम पेश करते हैं तो वही बात होगी। इसका समाधान विन्यास प्रबंधन है, जो सॉफ्टवेयर विकास का एक सामान्य हिस्सा है। किसी भी मामले में, यह समस्या तब उत्पन्न होती है जब आप पुस्तकालय बना रहे हों - यदि यह एक कोडबेस के भीतर है, तो बस अपने सहयोगियों से बात करें। – Marcin

+0

यह उस भाषा के संदर्भ में सच है जो सार्वजनिक/निजी के विचार से बहुत ढीला है। दोनों के बीच मजबूत भेद वाली एक भाषा "स्थिर एपीआई, परिवर्तनीय आंतरिक" दृष्टिकोण को आसान बना देगी; मैं अपरिवर्तनीय एपीआई के पीछे एक अपरिवर्तनीय एपीआई के पीछे हो सकता हूं। मैं इस तरह के भेद की कमी को एक समस्या पर विचार करता हूं, लेकिन मैं स्वीकार करता हूं कि अन्य लोग नहीं करते हैं। – Chris

0

mangling डबल के साथ होता है रेखांकित। एकल अंडरस्कोर अधिक "कृपया नहीं" हैं।

आपको सभी अभिभावक वर्गों के सभी विवरणों को जानने की आवश्यकता नहीं है (ध्यान दें कि गहरी विरासत आमतौर पर सबसे अच्छी तरह से बचाई जाती है), क्योंकि आप अभी भी dir() और मदद() और आत्मनिरीक्षण के किसी अन्य रूप को आ सकते हैं साथ में।

2

कितनी बार आप विरासत श्रृंखलाओं में आधार वर्गों को संशोधित करने के लिए एक वर्ग से विरासत को उसी उपनाम के साथ श्रृंखला के नीचे एक ही नाम के साथ संशोधित करने के लिए संशोधित करते हैं ???

कम ढिठाई से, हाँ, आप कोड आप के साथ काम कर रहे हैं पता करने के लिए की है। आप निश्चित रूप से को सार्वजनिक नामों का उपयोग करने के बारे में जानना है। पाइथन पाइथन है, आपके पूर्वजों के वर्गों द्वारा उपयोग में आने वाले सार्वजनिक नामों की खोज निजी लोगों की खोज के समान ही प्रयास करती है।

अजगर प्रोग्रामिंग के वर्षों में, मैंने कभी नहीं पाया है इस अभ्यास में एक मुद्दे के ज्यादा होने के लिए। जब आप इंस्टेंस वैरिएबल नाम दे रहे हों, तो आपको एक अच्छा विचार होना चाहिए कि (ए) एक नाम सामान्य है कि यह अन्य संदर्भों में उपयोग होने की संभावना है और (बी) जिस वर्ग को आप लिख रहे हैं वह एक में शामिल होने की संभावना है अन्य अज्ञात वर्गों के साथ विरासत पदानुक्रम। ऐसे मामलों में, आप जिन नामों का उपयोग कर रहे हैं, उनके बारे में थोड़ा अधिक सावधानी से सोचते हैं; self.value एक विशेषता नाम के लिए एक अच्छा विचार नहीं है, और न ही Adaptor एक महान श्रेणी का नाम है।

इसके विपरीत, मैं डबल अंडरस्कोर नाम के अति प्रयोग कई बार साथ कठिनाइयों में चलाने की है। पायथन पाइथन है, यहां तक ​​कि "निजी" नाम कक्षा के बाहर परिभाषित कोड द्वारा उपयोग किए जाते हैं। आपको लगता है कि बाहरी कार्य को "निजी" विशेषताओं तक पहुंचने के लिए हमेशा बुरा व्यवहार होगा, लेकिन getattr और hasattr जैसी चीज़ों के बारे में क्या होगा? उनमें से मंगलाचरण, वर्ग के अपने कोड में हो सकता है तो वर्ग अभी भी निजी विशेषताओं के इस्तेमाल के सभी नियंत्रित कर रहा है, लेकिन वे अभी भी आप नाम-mangling मैन्युअल कर के बिना काम नहीं करते। यदि पाइथन ने वास्तव में निजी चर लागू किए थे तो आप उन पर कार्यों का उपयोग नहीं कर सके। इन दिनों मैं मामलों के लिए डबल-अंडरस्कोर नाम आरक्षित करता हूं जब मैं एक सजावटी, मेटाक्लास, या मिक्सिन जैसे बहुत सामान्य जेनेरिक लिख रहा हूं जिसे इसे (अज्ञात) कक्षाओं के उदाहरणों के लिए "गुप्त विशेषता" जोड़ने की आवश्यकता होती है।

और रास्ते में मानक गतिशील भाषा तर्क है: वास्तविकता आप दावा "मेरे सॉफ्टवेयर काम करता है" को बनाने में बहुत औचित्य है करने के लिए अच्छी तरह से अपने कोड का परीक्षण करना है। इस तरह के परीक्षण गलती से नामांकन के कारण होने वाली बगों को याद करने की संभावना नहीं होगी। यदि आप वह परीक्षण नहीं कर रहे हैं, तो कई अधिक अनगिनत बग आकस्मिक नाम संघर्षों के मुकाबले अन्य माध्यमों द्वारा पेश किए जाएंगे।

संक्षेप में, निजी चर की कमी अभ्यास में बेवकूफ पायथन कोड में इतना बड़ा सौदा नहीं है, और वास्तविक निजी चर के अतिरिक्त आईएमएचओ के अन्य तरीकों से अधिक बार समस्याएं पैदा होती हैं।