किसी चीज को 'ट्राई' करने से बेहतर है कि आप अपवाद से बचने के लिए पहले अपवाद या परीक्षण को पकड़ लें।


139

क्या मुझे परीक्षण करना चाहिए कि ifकुछ वैध है या केवल tryइसे करना है और अपवाद को पकड़ना है?

  • क्या कोई ठोस दस्तावेज यह कह रहा है कि एक तरह से पसंद किया जाता है?
  • एक तरह से अधिक पायथोनिक है ?

उदाहरण के लिए, क्या मुझे:

if len(my_list) >= 4:
    x = my_list[3]
else:
    x = 'NO_ABC'

या:

try:
    x = my_list[3]
except IndexError:
    x = 'NO_ABC'

कुछ विचार ...
PEP 20 कहते हैं:

त्रुटियों को कभी भी चुपचाप नहीं गुजरना चाहिए।
जब तक स्पष्ट रूप से चुप नहीं कराया जाता।

क्या चुपचाप गुज़रने में त्रुटि के रूप में व्याख्या tryकरने के बजाय उपयोग करना चाहिए if? और यदि हां, तो क्या आप इसे इस तरह से उपयोग करके स्पष्ट रूप से चुप करा रहे हैं, इसलिए इसे ठीक बना रहे हैं?


मैं उन स्थितियों का उल्लेख नहीं कर रहा हूं जहां आप केवल 1 तरीके से काम कर सकते हैं; उदाहरण के लिए:

try:
    import foo
except ImportError:
    import baz

जवाबों:


161

आप को प्राथमिकता देनी चाहिए try/exceptसे अधिक if/elseहै, तो में है कि परिणाम

  • स्पीड-अप्स (उदाहरण के लिए अतिरिक्त लुकअप को रोककर)
  • क्लीनर कोड (कम लाइनें / पढ़ने में आसान)

अक्सर, ये हाथ से चलते हैं।


गति-अप

द्वारा एक लंबी सूची में एक तत्व खोजने की कोशिश करने के मामले में:

try:
    x = my_list[index]
except IndexError:
    x = 'NO_ABC'

जब indexसूची में है और इंडेक्सएयर आमतौर पर नहीं उठाया जाता है, तो सबसे अच्छा विकल्प है, को छोड़कर । इस तरह आप एक अतिरिक्त खोज की आवश्यकता से बचते हैं if index < len(my_list)

पायथन अपवादों के उपयोग को प्रोत्साहित करता है, जिसे आप संभालते हैं डाइव इन पायथन से एक वाक्यांश है । आपका उदाहरण न केवल अपवाद (इनायत) को संभालता है, बल्कि उसे चुपचाप पारित करने के बजाय , अपवाद केवल अनुक्रमणिका के असाधारण मामले में पाया जाता है (इसलिए शब्द अपवाद नहीं !)।


क्लीनर कोड

आधिकारिक पायथन डॉक्यूमेंटेशन में ईएएफपी का उल्लेख किया गया है : अनुमति की तुलना में माफी माँगने में आसान और रॉब नाइट नोट जो उन्हें बचने के बजाय त्रुटियों को पकड़ते हैं , क्लीनर में परिणाम कर सकते हैं , कोड को पढ़ना आसान है। उनका उदाहरण इसे इस तरह कहता है:

इससे भी बदतर (LBYL 'छलांग लगाने से पहले' देखें) :

#check whether int conversion will raise an error
if not isinstance(s, str) or not s.isdigit():
    return None
elif len(s) > 10:    #too many digits for int conversion
    return None
else:
    return int(s)

बेहतर (EAFP: अनुमति की तुलना में माफी के लिए पूछना आसान) :

try:
    return int(s)
except (TypeError, ValueError, OverflowError): #int conversion failed
    return None

if index in mylistपरीक्षण wether सूचकांक mylist का एक तत्व है, संभव सूचकांक नहीं। आप if index < len(mylist)इसके बजाय चाहते हैं।
येचू

1
यह समझ में आता है, लेकिन मैं कहां से दस्तावेज ढूंढता हूं जो यह स्पष्ट करता है कि इंट () के लिए क्या संभावित अपवाद फेंके जा सकते हैं। docs.python.org/3/library/functions.html#int मैं यहां इस जानकारी को खोजने में असमर्थ हूं।
BrutalSimplicity

इसके विपरीत, आप अपने जवाब में इस मामले को ( ऑफ डॉक से ) जोड़ सकते हैं , जब आपको इससे if/elseअधिक पसंद करना चाहिएtry/catch
rappongy

20

इस विशेष मामले में, आपको पूरी तरह से कुछ और उपयोग करना चाहिए:

x = myDict.get("ABC", "NO_ABC")

सामान्य तौर पर, हालांकि: यदि आप अक्सर असफल होने के लिए परीक्षण की अपेक्षा करते हैं, तो उपयोग करें if। यदि परीक्षण महंगा है, तो बस संचालन की कोशिश करना और अपवाद को पकड़ना यदि यह विफल रहता है, तो उपयोग करें try। यदि इनमें से कोई भी स्थिति लागू नहीं होती है, तो जो भी पढ़ता है उसे आसान बनाएं।


1
कोड नमूने के तहत स्पष्टीकरण के लिए +1, जो ऑन स्पॉट है।
ktdrv

4
मुझे लगता है कि यह बहुत स्पष्ट है कि यह वह नहीं पूछ रहा है, और उसने अब इसे और भी स्पष्ट करने के लिए पोस्ट को संपादित किया है।
agf

9

गार्ड के अंदर के बजाय सीधे tryऔर exceptसीधे उपयोग करना ifचाहिए, अगर दौड़ की स्थिति की कोई संभावना है तो हमेशा किया जाना चाहिए । उदाहरण के लिए, यदि आप यह सुनिश्चित करना चाहते हैं कि कोई निर्देशिका मौजूद है, तो ऐसा न करें:

import os, sys
if not os.path.isdir('foo'):
  try:
    os.mkdir('foo')
  except OSError, e
    print e
    sys.exit(1)

यदि कोई अन्य थ्रेड या प्रक्रिया के बीच निर्देशिका बनाता है , isdirऔर mkdirआप बाहर निकल जाएंगे। इसके बजाय, यह करें:

import os, sys, errno
try:
  os.mkdir('foo')
except OSError, e
  if e.errno != errno.EEXIST:
    print e
    sys.exit(1)

केवल तभी बाहर निकलेगा जब 'फू' डायरेक्टरी नहीं बनाई जा सकती।


7

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

अपवाद के लिए इस्तेमाल किया जाना चाहिए:

  1. वे चीजें जो अप्रत्याशित हैं, या ...
  2. ऐसी चीज़ें जहाँ आपको एक से अधिक स्तर के तर्क देने की आवश्यकता होती है (जैसे जहाँ a break आपको बहुत दूर नहीं जाना पड़ता है), या ...
  3. ऐसी चीजें जहां आप नहीं जानते कि समय के आगे अपवाद को संभालने के लिए क्या हो रहा है, या ...
  4. चीजें जहां असफलता के लिए समय से पहले जाँच करना महंगा है (बस ऑपरेशन के प्रयास के सापेक्ष)

ध्यान दें कि, वास्तविक उत्तर "न तो" है - उदाहरण के लिए, अपने पहले उदाहरण में, आपको वास्तव में क्या करना चाहिए , बस .get()एक डिफ़ॉल्ट प्रदान करने के लिए उपयोग किया जाता है:

x = myDict.get('ABC', 'NO_ABC')

सिवाय इसके कि if 'ABC' in myDict: x = myDict['ABC']; else: x = 'NO_ABC'वास्तव में उपयोग करने की तुलना में अक्सर तेज होता है get, दुर्भाग्य से। यह नहीं कहना कि यह सबसे महत्वपूर्ण मानदंड है, लेकिन इसके बारे में जागरूक होना कुछ है।
agf

@agf: स्पष्ट और संक्षिप्त कोड लिखने के लिए बेहतर है। यदि बाद में किसी चीज़ को अनुकूलित किया जाना है, तो वापस आना आसान है और इसे फिर से लिखना है, लेकिन c2.com/cgi/wiki?PrematureOptimization
Amber

मुझे पता है कि; मेरी बात यह थी कि if / elseऔर try / exceptअपनी जगह हो सकता है , भले ही मामला विशेष विकल्प हैं क्योंकि वे विभिन्न प्रदर्शन विशेषताएं हैं।
agf

@ ओफ़्फ़, क्या आप जानते हैं कि भविष्य के संस्करणों में प्राप्त () विधि में सुधार होगा (कम से कम) जितना तेज़ी से स्पष्ट रूप से दिख रहा है? वैसे, जब दो बार दिख रहा है (जैसे कि 'एबीसी' में डी: डी ['एबीसी']), तो कोशिश है: डी ['एबीसी'] कीर को छोड़कर: ... सबसे तेज़ नहीं?
रेमी

2
@ रीमी .get()पायथन स्तर पर विशेषता लुकअप और फ़ंक्शन कॉल ओवरहेड का धीमा हिस्सा है; मूल रूप से अंतर्निहित इन्स पर खोजशब्दों का उपयोग करना सी। के लिए सही है। मुझे नहीं लगता कि यह जल्द ही किसी भी समय बहुत तेज़ हो जाएगा। जहाँ तक ifबनाम try, श्रुतलेख पढ़ें । () विधि एक सूचक को लौटाती है जिसमें कुछ प्रदर्शन जानकारी होती है। मुहावरों के मामले में हिट का अनुपात ( tryयदि कुंजी हमेशा मौजूद रहती है तो तेज हो सकता है) जैसा कि शब्दकोश का आकार है।
एएफएफ

5

जैसा कि अन्य पदों का उल्लेख है, यह स्थिति पर निर्भर करता है। पहले से ही अपने डेटा की वैधता की जाँच करने के स्थान पर, प्रयोग करने के अलावा / उपयोग के साथ कुछ खतरे हैं, खासकर जब इसका उपयोग बड़ी परियोजनाओं पर किया जाता है।

  • ट्राई ब्लॉक के कोड में अपवाद के पकड़े जाने से पहले सभी तरह के कहर बरपाने ​​का मौका हो सकता है - अगर आप एक बयान के साथ पहले से जाँच कर लें कि आप इससे बच सकते हैं।
  • यदि आपके प्रयास ब्लॉक में कहा गया कोड एक सामान्य अपवाद प्रकार उठाता है, जैसे TypeError या ValueError, तो आप वास्तव में उसी अपवाद को नहीं पकड़ सकते हैं जिसे आप पकड़ने की उम्मीद कर रहे थे - यह कुछ और हो सकता है जो समान अपवाद वर्ग को उठाने से पहले या बाद में भी मिल रहा हो वह रेखा जहां आपका अपवाद उठाया जा सकता है।

उदाहरण के लिए, मान लीजिए कि आपके पास था:

try:
    x = my_list[index_list[3]]
except IndexError:
    x = 'NO_ABC'

IndexError इंडेक्स_लिस्ट या my_list के एक तत्व को प्राप्त करने की कोशिश करते समय क्या हुआ, इसके बारे में कुछ नहीं कहता है।


4

अगर चुपचाप पास होने वाली त्रुटि के रूप में व्याख्या की जाए, तो इसके बजाय कोशिश का उपयोग करना चाहिए? और यदि हां, तो क्या आप इसे इस तरह से उपयोग करके स्पष्ट रूप से चुप करा रहे हैं, इसलिए इसे ठीक बना रहे हैं?

प्रयोग tryयह स्वीकार कर रहा है कि एक त्रुटि पारित हो सकती है, जो चुपचाप पास होने के विपरीत है। उपयोग करने exceptके कारण यह बिल्कुल नहीं गुजर रहा है।

उपयोग try: except:उन मामलों में पसंद किया जाता है जहां if: else:तर्क अधिक जटिल है। सरल जटिल से बेहतर है; जटिल से जटिल बेहतर है; और अनुमति की तुलना में माफी मांगना आसान है।

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

हालाँकि, आपके विशेष उदाहरण में, न तो उचित है:

x = myDict.get('ABC', 'NO_ABC')

हर कोई इसका कारण बता रहा है - भले ही आप सामान्य रूप से समझने की अपनी इच्छा को स्वीकार करते हैं, और एक बेहतर उदाहरण के साथ आने में असमर्थता - यह है कि समकक्ष पक्ष-कदम वास्तव में काफी मामलों में मौजूद हैं, और उनकी तलाश है समस्या को हल करने में पहला कदम।


3

जब भी आप try/exceptनियंत्रण प्रवाह के लिए उपयोग करते हैं, अपने आप से पूछें:

  1. क्या यह देखना आसान है कि tryब्लॉक कब सफल होता है और कब विफल होता है?
  2. क्या आप ब्लॉक के अंदर सभी दुष्प्रभावों से अवगत हैं try?
  3. क्या आप उन सभी मामलों से अवगत हैं जिनमें tryब्लॉक अपवाद को फेंकता है?
  4. यदि tryब्लॉक के कार्यान्वयन में परिवर्तन होता है, तो क्या आपका नियंत्रण प्रवाह अभी भी अपेक्षित व्यवहार करेगा?

यदि इनमें से किसी एक या अधिक प्रश्न का उत्तर 'नहीं' है, तो पूछने के लिए बहुत क्षमा करना पड़ सकता है; अपने भविष्य से सबसे अधिक संभावना है।


एक उदाहरण। मैंने हाल ही में एक बड़ी परियोजना में कोड देखा जो इस तरह से देखा:

try:
    y = foo(x)
except ProgrammingError:
    y = bar(x)

प्रोग्रामर से बात करते हुए यह कहा गया कि इच्छित नियंत्रण प्रवाह था:

यदि x पूर्णांक है, तो y = foo (x) करें।

यदि x पूर्णांकों की सूची है, तो y = bar (x) करें।

इसने काम किया क्योंकि fooडेटाबेस क्वेरी और क्वेरी सफल होगी यदि xएक पूर्णांक था और ProgrammingErrorयदि xएक सूची थी तो उसे फेंक दें ।

उपयोग करना try/exceptयहाँ एक बुरा विकल्प है:

  1. अपवाद का नाम, ProgrammingErrorवास्तविक समस्या को दूर नहीं करता है (जो xपूर्णांक नहीं है), जो कि यह देखना मुश्किल है कि क्या चल रहा है।
  2. ProgrammingErrorएक डेटाबेस कॉल, जो कचरे के समय के दौरान उठाया है। अगर यह fooएक अपवाद फेंकता है, या किसी अन्य प्रणाली की स्थिति बदल देता है इससे पहले कि यह डेटाबेस के लिए कुछ लिखता है कि चीजें वास्तव में भयानक हो जाएगा ।
  3. पूर्णांक की सूची ProgrammingErrorहोने पर ही उठाया जाता है तो यह स्पष्ट नहीं है x। उदाहरण के लिए मान लीजिए कि एक टाइपो fooडेटाबेस क्वेरी है। यह भी एक बढ़ा सकता है ProgrammingError। परिणाम यह है कि bar(x)अब भी कहा जाता है जब xएक पूर्णांक है। यह गुप्त अपवादों को बढ़ा सकता है या अप्रत्याशित परिणाम उत्पन्न कर सकता है।
  4. try/exceptब्लॉक के सभी भावी कार्यान्वयन के लिए एक आवश्यकता कहते हैं foo। जब भी हम बदलते हैं foo, तो हमें अब यह सोचना चाहिए कि यह सूचियों को कैसे संभालता है और यह सुनिश्चित करता है कि यह फेंकता है ProgrammingErrorया नहीं, कहे, AttributeErrorया कोई त्रुटि नहीं है।

0

एक सामान्य अर्थ के लिए, आप पायथन: अपवादों में मुहावरों और विरोधी मुहावरों को पढ़ने पर विचार कर सकते हैं ।

आपके विशेष मामले में, जैसा कि दूसरों ने कहा है, आपको उपयोग करना चाहिए dict.get():

प्राप्त करें (कुंजी [, डिफ़ॉल्ट])

कुंजी का मान लौटाएं यदि कुंजी शब्दकोश में है, तो डिफ़ॉल्ट रूप से। यदि डिफॉल्ट नहीं दिया गया है, तो यह किसी को भी डिफॉल्ट नहीं करता है, ताकि यह तरीका कभी भी कीरर न उठे।


मुझे नहीं लगता कि लिंक इस स्थिति को बिल्कुल कवर करता है। इसके उदाहरण उन चीजों को संभालने के बारे में हैं जो वास्तविक त्रुटियों का प्रतिनिधित्व करते हैं , न कि इस बात के बारे में कि अपेक्षित स्थितियों के लिए अपवाद हैंडलिंग का उपयोग करना है या नहीं।
agf

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