आम सहमति "अपवादों का उपयोग नहीं करती!" ज्यादातर अन्य भाषाओं से आता है और यहां तक कि कभी-कभी पुराना हो जाता है।
C ++ में, "स्टैक अनइंडिंग" के कारण एक अपवाद को फेंकना बहुत महंगा है । प्रत्येक स्थानीय चर घोषणा with
पायथन में एक बयान की तरह है , और उस चर में वस्तु विनाशकों को चला सकती है। ये विध्वंसक निष्पादित किए जाते हैं जब एक अपवाद फेंक दिया जाता है, लेकिन एक समारोह से लौटते समय भी। यह "RAII मुहावरा" एक अभिन्न भाषा की विशेषता है और मजबूत, सही कोड लिखने के लिए सुपर महत्वपूर्ण है - इसलिए RAII बनाम सस्ते अपवाद एक ट्रेडऑफ़ था जिसे C ++ ने RAII के लिए तय किया।
प्रारंभिक C ++ में, बहुत सारे कोड अपवाद-सुरक्षित तरीके से नहीं लिखे गए थे: जब तक आप वास्तव में RAII का उपयोग नहीं करते हैं, स्मृति और अन्य संसाधनों को लीक करना आसान है। इसलिए अपवादों को फेंकने से वह कोड गलत हो जाएगा। C ++ मानक लाइब्रेरी अपवादों का उपयोग करने के बाद भी यह उचित नहीं है: आप अपवाद नहीं दिखा सकते हैं जो मौजूद नहीं हैं। हालाँकि, C ++ के साथ C कोड को जोड़ते समय अपवाद अभी भी एक समस्या है।
जावा में, हर अपवाद में एक संबद्ध स्टैक ट्रेस होता है। स्टैक ट्रेस बहुत मूल्यवान है जब त्रुटियों को डीबग करना होता है, लेकिन व्यर्थ प्रयास तब होता है जब अपवाद कभी मुद्रित नहीं किया जाता है, उदाहरण के लिए क्योंकि यह केवल नियंत्रण प्रवाह के लिए उपयोग किया गया था।
इसलिए उन भाषाओं में अपवाद "बहुत महंगे हैं" जिनका उपयोग नियंत्रण प्रवाह के रूप में किया जाना है। पायथन में यह एक मुद्दे से कम है और अपवाद बहुत सस्ते हैं। इसके अतिरिक्त, पायथन भाषा पहले से ही कुछ ओवरहेड से ग्रस्त है, जो अन्य नियंत्रण प्रवाह निर्माणों की तुलना में अपवादों की लागत को ध्यान नहीं देता है: उदाहरण के लिए, यदि एक स्पष्ट सदस्यता परीक्षण के साथ एक तानाशाही प्रविष्टि मौजूद if key in the_dict: ...
है तो आम तौर पर बस प्रवेश the_dict[key]; ...
और जाँच की पहुँच से ठीक तेज़ है यदि आप एक KeyError प्राप्त करें। कुछ अभिन्न भाषा सुविधाएँ (जैसे जनरेटर) अपवादों के संदर्भ में डिज़ाइन की गई हैं।
इसलिए जबकि पायथन में अपवादों से विशेष रूप से बचने का कोई तकनीकी कारण नहीं है, फिर भी यह सवाल है कि क्या आपको वापसी मूल्यों के बजाय उनका उपयोग करना चाहिए। अपवादों के साथ डिज़ाइन-स्तरीय समस्याएं हैं:
वे बिल्कुल स्पष्ट नहीं हैं। आप आसानी से एक फ़ंक्शन को नहीं देख सकते हैं और देख सकते हैं कि यह किस अपवाद को फेंक सकता है, इसलिए आप हमेशा नहीं जानते कि क्या पकड़ना है। वापसी मूल्य अधिक अच्छी तरह से परिभाषित हो जाता है।
अपवाद गैर-स्थानीय नियंत्रण प्रवाह है जो आपके कोड को जटिल बनाता है। जब आप एक अपवाद फेंकते हैं, तो आपको पता नहीं होता है कि नियंत्रण प्रवाह फिर से कहाँ शुरू होगा। उन त्रुटियों के लिए जिन्हें तुरंत नियंत्रित नहीं किया जा सकता है, यह संभवतः एक अच्छा विचार है, जब किसी शर्त के अपने कॉलर को सूचित करना यह पूरी तरह अनावश्यक है।
पायथन संस्कृति आम तौर पर अपवादों के पक्ष में है, लेकिन ओवरबोर्ड पर जाना आसान है। एक list_contains(the_list, item)
फ़ंक्शन की कल्पना करें जो यह जांचता है कि सूची में उस आइटम के बराबर आइटम है या नहीं। यदि परिणाम अपवादों के माध्यम से संप्रेषित होता है जो बिल्कुल कष्टप्रद है, क्योंकि हमें इसे इस तरह से कॉल करना होगा:
try:
list_contains(invited_guests, person_at_door)
except Found:
print("Oh, hello {}!".format(person_at_door))
except NotFound:
print("Who are you?")
एक बूल लौटना ज्यादा स्पष्ट होगा:
if list_contains(invited_guests, person_at_door):
print("Oh, hello {}!".format(person_at_door))
else:
print("Who are you?")
यदि फ़ंक्शन पहले से ही मान लौटाने वाला है, तो विशेष शर्तों के लिए एक विशेष मान वापस करना त्रुटि-प्रवण है, क्योंकि लोग इस मान की जांच करना भूल जाएंगे (यह संभवतः C में समस्याओं का 1/3 कारण है)। एक अपवाद आमतौर पर अधिक सही होता है।
एक अच्छा उदाहरण एक pos = find_string(haystack, needle)
फ़ंक्शन है जो needle
`हैस्टैक स्ट्रिंग में स्ट्रिंग की पहली घटना के लिए खोज करता है , और प्रारंभ स्थिति देता है। लेकिन क्या होगा अगर वे हिस्टैक-स्ट्रिंग में सुई-स्ट्रिंग शामिल नहीं करते हैं?
सी द्वारा हल और पायथन द्वारा नकल एक विशेष मूल्य वापस करना है। सी में यह एक शून्य सूचक है, पायथन में यह है -1
। यह आश्चर्यजनक परिणाम देगा जब स्थिति को जाँच के बिना एक स्ट्रिंग सूचकांक के रूप में उपयोग किया जाता है, विशेष रूप -1
से पायथन में एक वैध सूचकांक के रूप में। C में, आपका NULL पॉइंटर कम से कम आपको segfault देगा।
PHP में, एक अलग प्रकार का एक विशेष मान लौटाया जाता है: FALSE
पूर्णांक के बजाय बूलियन । जैसा कि यह पता चलता है कि यह वास्तव में भाषा के अंतर्निहित रूपांतरण नियमों के कारण बेहतर नहीं है (लेकिन ध्यान दें कि पायथन में बूलियन को भी चींटियों के रूप में इस्तेमाल किया जा सकता है!)। लगातार प्रकार नहीं लौटाने वाले कार्यों को आम तौर पर बहुत भ्रमित माना जाता है।
एक अधिक मजबूत संस्करण एक अपवाद फेंकने के लिए होता है जब स्ट्रिंग नहीं पाया जा सकता है, जो यह सुनिश्चित करता है कि सामान्य नियंत्रण प्रवाह के दौरान गलती से एक साधारण मूल्य के स्थान पर विशेष मूल्य का उपयोग करना असंभव है:
try:
pos = find_string(haystack, needle)
do_something_with(pos)
except NotFound:
...
वैकल्पिक रूप से, हमेशा एक प्रकार का रिटर्न जो सीधे इस्तेमाल नहीं किया जा सकता है, लेकिन पहले इसे अनफ्रीप्ड किया जाना चाहिए, उदाहरण के लिए इस्तेमाल किया जा सकता है, उदाहरण के लिए बूल टुपल जहां बूलियन इंगित करता है कि क्या अपवाद हुआ या यदि परिणाम उपयोग करने योग्य है। फिर:
pos, ok = find_string(haystack, needle)
if not ok:
...
do_something_with(pos)
यह आपको समस्याओं को तुरंत संभालने के लिए मजबूर करता है, लेकिन यह बहुत जल्दी परेशान हो जाता है। यह आपको आसानी से कार्य करने से रोकता है। प्रत्येक फ़ंक्शन कॉल को अब कोड की तीन पंक्तियों की आवश्यकता होती है। गोलंग एक ऐसी भाषा है जो सोचती है कि यह उपद्रव सुरक्षा के लायक है।
इसलिए संक्षेप में, अपवाद पूरी तरह से समस्याओं के बिना नहीं हैं और निश्चित रूप से इसका अत्यधिक उपयोग किया जा सकता है, खासकर जब वे "सामान्य" वापसी मूल्य को प्रतिस्थापित करते हैं। लेकिन जब विशेष परिस्थितियों का संकेत देने के लिए उपयोग किया जाता है (जरूरी नहीं कि सिर्फ त्रुटियां), तो अपवाद आपको एपीआई विकसित करने में मदद कर सकते हैं जो साफ, सहज, उपयोग करने में आसान और दुरुपयोग करने में मुश्किल हैं।