2013-08-30 5 views
13

यह प्रश्न this one asked earlier और this one पर भी बनाता है, लेकिन एक अधिक सूक्ष्म बिंदु को संबोधित करता है, विशेष रूप से, "आंतरिक वर्ग" के रूप में क्या मायने रखता है?पायथन कक्षा के नामों में अग्रणी अंडरस्कोर

यहाँ मेरी स्थिति है। मैं एमएस ऑफ़िस फ़ाइलें, जिसमें वर्गों में से कई बाहर से निर्माण किया जा करने के लिए नहीं कर रहे हैं जोड़ तोड़ के लिए एक अजगर लाइब्रेरी बनाना रहा हूँ, उनके तरीकों में से अभी तक कई एपीआई के महत्वपूर्ण हिस्से हैं। उदाहरण के लिए:

class _Slide(object): 
    def add_shape(self): 
     ... 

_Slide बाहर से निर्माण किया जा करने के लिए, पुस्तकालय की एक अंतिम-उपयोगकर्ता के रूप में आप Presentation.add_slide() को फोन करके एक नई स्लाइड प्राप्त नहीं है। हालांकि, एक बार आप एक स्लाइड है आप निश्चित रूप से add_shape() कॉल करने के लिए सक्षम होना चाहते हैं। तो विधि एपीआई का हिस्सा है लेकिन कन्स्ट्रक्टर नहीं है। यह स्थिति लाइब्रेरी में दर्जनों बार उत्पन्न होती है क्योंकि केवल प्रेजेंटेशन क्लास में बाहरी/एपीआई कन्स्ट्रक्टर होता है।

PEP8 क्या एक आंतरिक वर्ग के रूप में गिना जाता है के विस्तार के बिना "आंतरिक वर्ग" के संदर्भ बनाने इस मुद्दे पर अस्पष्ट है,। इस मामले में मुझे लगता है कि कोई कह सकता है कि वर्ग "आंशिक रूप से आंतरिक" है।

  1. निर्माता और वर्ग के "सार्वजनिक/एपीआई" तरीकों सभी के उपयोग के लिए उपलब्ध हैं:

    समस्या मैं केवल कम से कम तीन अलग स्थितियों में भेद करने के दो अंकन है।

  2. निर्माता प्रयोग किया जाता है नहीं करने के लिए किया जाएगा, लेकिन "सार्वजनिक/एपीआई" वर्ग के तरीके हैं।
  3. कक्षा वास्तव में आंतरिक है, इसमें कोई सार्वजनिक एपीआई नहीं है, और मैं इसे भविष्य में रिलीज में बदलने या हटाने का अधिकार सुरक्षित रखता हूं।

मैं ध्यान दें एक संचार के नजरिए से, वहाँ बाहरी API के स्पष्ट अभिव्यक्ति (पुस्तकालय अंतिम-उपयोगकर्ता दर्शकों) और आंतरिक एपीआई (डेवलपर ऑडियंस) के बीच एक संघर्ष है। एक अंत उपयोगकर्ता के लिए, बुला _Slide() verboten है/पर-खुद जोखिम। हालांकि यह आंतरिक एपीआई का एक खुश सदस्य है और _random_helper_method() से अलग है जिसे केवल _Slide() के भीतर से बुलाया जाना चाहिए।

क्या आपके पास इस प्रश्न पर एक दृष्टिकोण है जो मेरी मदद कर सकता है? क्या सम्मेलन यह निर्देश देता है कि मैं एंड-यूजर एपीआई में स्पष्टता के लिए लड़ने के लिए कक्षा के नाम पर अपने "एकल-अग्रणी-अंडरस्कोर" गोला बारूद का उपयोग करता हूं या क्या मैं खुद को और अन्य डेवलपर्स से संवाद करने के लिए इसे सुरक्षित रखने के बारे में अच्छा महसूस कर सकता हूं, जब कक्षा एपीआई वास्तव में है निजी और उपयोग नहीं किया जाना चाहिए, उदाहरण के लिए, मॉड्यूल के बाहर वस्तुओं द्वारा यह रहता है क्योंकि यह एक कार्यान्वयन विस्तार है जो बदल सकता है?


अद्यतन: आगे प्रतिबिंब के कुछ वर्षों के बाद, मैं जब कि उनके मॉड्यूल के बाहर एक वर्ग के रूप में पहुँचा जा करने का इरादा नहीं कर रहे हैं वर्गों का नामकरण एक अग्रणी अंडरस्कोर का उपयोग कर के सम्मेलन में बसे है (फ़ाइल)। इस तरह की पहुंच आम तौर पर उस वर्ग के किसी ऑब्जेक्ट को तुरंत चालू करने या कक्षा विधि तक पहुंचने के लिए होती है।

यह मॉड्यूल के उपयोगकर्ताओं को प्रदान करता है (अक्सर स्वयं ही मूलभूत संकेतक: "यदि एक प्रमुख अंडरस्कोर वाला क्लास नाम एक आयात कथन में प्रकट होता है, आप कुछ गलत कर रहे हैं। " (इकाई परीक्षण मॉड्यूल इस नियम के अपवाद हैं, इस तरह के आयात अक्सर एक "आंतरिक" वर्ग के लिए इकाई परीक्षण में दिखाई दे सकते हैं।)

ध्यान दें कि यह वर्ग के लिए उपयोग है।मॉड्यूल के बाहर उस श्रेणी (प्रकार) के ऑब्जेक्ट तक पहुंच, शायद किसी फैक्ट्री या जो कुछ भी प्रदान की गई हो, पूरी तरह से ठीक है और शायद अपेक्षित है। मुझे लगता है कि उनसे बनाए गए वस्तुओं से वर्गों को अलग करने में यह विफलता मेरे शुरुआती भ्रम की वजह से थी।

इस सम्मेलन में from module import * कथन बनाते समय इन कक्षाओं को शामिल करने का साइड लाभ भी है। हालांकि मैं इन्हें अपने कोड में कभी भी उपयोग नहीं करता हूं और उन्हें टालने की सलाह देता हूं, यह एक उचित व्यवहार है क्योंकि उन वर्ग पहचानकर्ताओं को मॉड्यूल इंटरफ़ेस का हिस्सा बनने का इरादा नहीं है।

यह परीक्षण के वर्षों के बाद मेरा व्यक्तिगत "सर्वोत्तम अभ्यास" है, और निश्चित रूप से "सही" तरीका नहीं है। आपकी माइलेज भिन्न हो सकती है।

+0

मुझे यह तय करने में थोड़ा सा लगा कि यह मुख्य रूप से राय-आधारित के रूप में नहीं गिना जाना चाहिए। यद्यपि शब्द में सुधार किया जा सकता है। – user2357112

+0

'Presentation.add_slide()' को कॉल करने के बाद, जिस स्लाइड को बनाया गया था, उसे कैसे पहुंचाया जा सकता है? यदि यह '_Slide()' उदाहरण के माध्यम से है, तो उपयोगकर्ता के पास '_Slide' प्रभावी रूप से एक सार्वजनिक वर्ग है। – martineau

+0

@ मार्टिनौ: मुझे लगता है कि यह काफी जवाब है। आपके द्वारा वर्णित निष्कर्ष के बाद मैं यह आया हूं कि यदि कक्षा का कोई हिस्सा नहीं है (कन्स्ट्रक्टर, विधियों) का उपयोग * मॉड्यूल के बाहर * होता है। और कक्षा के नामों में एक अग्रणी अंडरस्कोर का उपयोग कक्षाओं के लिए किया जाना चाहिए जो इस विवरण को पूरा करते हैं। यदि आप एक उत्तर में डाल देंगे तो मैं इसे स्वीकार करूंगा। – scanny

उत्तर

3

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

इस तथ्य यह है कि उदाहरणों केवल एक Presentation की add_slide() विधि बुला क्योंकि फोन करने वाले तो मुक्त (और अधिक होने की संभावना) की आवश्यकता हो जाएगा द्वारा परोक्ष रूप से बनाया जाएगा यह बाद में हेरफेर करने के लिए उदाहरण के तरीकों कॉल करने के लिए के बावजूद सच है। मेरी राय में वास्तव में निजी वर्ग केवल उस वर्ग के तरीकों से पहुंचा जा सकता है, जिसका "स्वामित्व" है।

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

0

__all__ = ['Presentation'] मॉड्यूल में प्रस्तुति वर्ग को छोड़कर help() जैसे कार्यों से सभी कक्षाओं को छुपाता है। लेकिन डेवलपर्स के पास अभी भी कॉल कन्स्ट्रक्टर और बाहर से तरीकों तक पहुंच है।

4

मुझे लगता है कि मार्टिनौ का जवाब एक अच्छा है, निश्चित रूप से सबसे सरल और इसमें कोई संदेह नहीं है कि अधिकांश पाइथोनिक।

हालांकि, इसका कोई मतलब नहीं है।

इंटरफ़ेस प्रकार के हिस्से के रूप में सार्वजनिक विधियों को परिभाषित करने के लिए अक्सर उपयोग की जाने वाली तकनीक; उदाहरण के लिए zope.interface.Interface मोड़ वाले ढांचे में व्यापक रूप से उपयोग किया जाता है। आधुनिक पाइथन शायद उसी प्रभाव के लिए abc.ABCMeta का उपयोग करेगा। अनिवार्य रूप से, सार्वजनिक विधि Presentation.add_slide को AbstractSlide के कुछ उदाहरण लौटने के रूप में दस्तावेज किया गया है, जिसमें अधिक सार्वजनिक विधियां हैं; लेकिन चूंकि AbstractSlide का उदाहरण बनाना संभव नहीं है, इसलिए कोई भी बनाने का कोई सार्वजनिक तरीका नहीं है।

वह तकनीक विशेष रूप से आसान हो सकती है, क्योंकि अमूर्त प्रकार के नकली उदाहरण बनाए जा सकते हैं जो दावा कर सकते हैं कि केवल सार्वजनिक विधियों को बुलाया जाता है; यूनिट परीक्षण के लिए काफी उपयोगी (विशेष रूप से आपकी लाइब्रेरी के उपयोगकर्ताओं के लिए, ताकि वे सुनिश्चित कर सकें कि वे केवल सार्वजनिक इंटरफेस का उपयोग कर रहे हैं)।

एक और विकल्प; चूंकि स्लाइड वर्ग के उदाहरण बनाने का एकमात्र सार्वजनिक रूप से उपलब्ध तरीका Presentation.add_slide के माध्यम से है; आप उस को सचमुच निर्माता बना सकते हैं। इस तरह शायद कुछ मेटाक्लास शेंगेनगान की आवश्यकता होगी, ऐसा कुछ करना चाहिए।

from functools import partial 

class InstanceConstructor(type): 
    def __get__(cls, instance, owner): 
     if instance is not None: 
      return partial(cls, instance) 
     return cls 

और बस वर्ग के __init__ में add_slide व्यवहार को परिभाषित:

>>> class Presentation(object): 
...  def __init__(self): 
...   self.slides = [] 
... 
...  class add_slide(object): 
...   __metaclass__ = InstanceConstructor 
... 
...   def __init__(slide, presentation, color): 
...    slide.color = color 
...    presentation.slides.append(slide) 
... 
>>> p = Presentation() 
>>> p.add_slide('red') 
<instance_ctor.add_slide object at ...> 
>>> p.slides 
[<instance_ctor.add_slide object at ...>] 
>>> p.slides[0].color 
'red' 
+0

मुझे लगता है कि यह सबसे अच्छा जवाब है। मेरा एकमात्र quibble यह है कि मुझे लगता है कि प्रस्तुति उदाहरण के लिए 'self' का उपयोग' Presentation.add_slide .__ init__' में भ्रमित है। मैं सुझाव दूंगा कि या तो 'स्वयं' स्लाइड (सामान्य, गैर-नेस्टेड कक्षा में), या 'स्वयं' सम्मेलन को पूरी तरह से छोड़कर 'def __init __ (स्लाइड, प्रेजेंटेशन, रंग)' के लिए जा रहा है। – Blckknght

+1

आपके समर्थन के लिए धन्यवाद, लेकिन मेरा दूसरा सुझाव वास्तव में एक मनोरंजन है। मेरा सुझाव यह नहीं होगा। या तो स्वीकार किए गए उत्तर में वर्ग को सार्वजनिक बनाएं, या सार्वजनिक इंटरफ़ेस के लिए एक अमूर्त वर्ग का उपयोग करें। – SingleNegationElimination

1

क्या एक "आंतरिक" वर्ग है सम्मेलन की बात है, जिसके कारण पीईपी को परिभाषित नहीं किया है शब्द, लेकिन यदि आप इन्हें अपने उपयोगकर्ताओं को उजागर कर रहे हैं (इस वर्ग को वापस करने वाले तरीकों को प्रदान करना, या इस कक्षा को पारित करने पर भरोसा करना) यह वास्तव में "आंतरिक" नहीं है।

आपके पास तीन विकल्प हैं, वास्तव में। सबसे पहले दस्तावेज बनाना और इस वर्ग को कैसे बनाया जा सकता है, इस बारे में अपना इरादा स्पष्ट कर सकता है, दूसरे शब्दों में आपके उपयोगकर्ताओं को कक्षा के उदाहरणों का निर्माण और उपयोग करने की अनुमति देना और यह कैसे करना है, यह दस्तावेज करना। चूंकि आप इन स्लाईड ऑब्जेक्ट्स को ट्रैक करने वाली अपनी उच्च स्तरीय कक्षा चाहते हैं, तो कुछ ऐसा करें जो कन्स्ट्रक्टर इंटरफ़ेस अनिवार्य है और सेट अप करता है, ताकि आपके मॉड्यूल के उपयोगकर्ता इन्हें आपके जैसे ही बना सकें।

एक और इस वर्ग के उन पहलुओं को लपेटना होगा जो आप इस उदाहरण को बनाने और प्रबंधित करने वाले वर्ग में बेनकाब करना चाहते हैं, दूसरे शब्दों में यह वास्तव में आंतरिक वर्ग बनाते हैं। यदि आपको केवल एक विधि का खुलासा करने की आवश्यकता है (कहें, add_shape()) यह बहुत उचित हो सकता है। यदि आप इस कक्षा में इंटरफेस का एक बड़ा हिस्सा उजागर करना चाहते हैं, हालांकि, यह बेकार दिखने लगता है।

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

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

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