अगर अजगर में कोशिश बनाम का उपयोग करना


145

क्या यह तय करने के लिए कोई तर्क है कि किसी एक का उपयोग करने के लिए कौन सा निर्माण करता है tryया ifक्या करता है?

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

result = function();
if (result):
    for r in result:
        #process items

या

result = function();
try:
    for r in result:
        #process items
except TypeError:
    pass;

संबंधित चर्चा:

पायथन में सदस्य अस्तित्व के लिए जाँच करना


इस बात को ध्यान में रखें कि यदि आपके #process आइटम श्लोक को टाइप करने के लिए उत्तरदायी है, तो आपको एक और कोशिश में लिपटने की आवश्यकता है: सिवाय: ब्लॉक के। इस विशिष्ट उदाहरण के लिए मैं सिर्फ एक का उपयोग करके करूँगा:
Richo

जवाबों:


237

आप अक्सर सुनते हैं कि पायथन एलबीवाईएल शैली (" आप छलांग लगाने से पहले देखो ") पर ईएएफपी शैली (" अनुमति की तुलना में माफी मांगना आसान है") को प्रोत्साहित करते हैं। मेरे लिए, यह दक्षता और पठनीयता की बात है।

आपके उदाहरण में (यह कहें कि किसी सूची या खाली स्ट्रिंग को वापस करने के बजाय, फ़ंक्शन को एक सूची या वापस लौटना था None), यदि आप उम्मीद करते हैं कि 99% समय resultमें वास्तव में कुछ चलने योग्य होगा, तो मैं try/exceptदृष्टिकोण का उपयोग करूंगा । यह तेजी से होगा अगर अपवाद वास्तव में असाधारण हैं। अगर resultहै None, समय की 50% से अधिक तो का उपयोग कर ifशायद बेहतर है।

कुछ मापों के साथ इसका समर्थन करने के लिए:

>>> import timeit
>>> timeit.timeit(setup="a=1;b=1", stmt="a/b") # no error checking
0.06379691968322732
>>> timeit.timeit(setup="a=1;b=1", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.0829463709378615
>>> timeit.timeit(setup="a=1;b=0", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.5070195056614466
>>> timeit.timeit(setup="a=1;b=1", stmt="if b!=0:\n a/b")
0.11940114974277094
>>> timeit.timeit(setup="a=1;b=0", stmt="if b!=0:\n a/b")
0.051202772912802175

इसलिए, जबकि एक ifबयान में हमेशा आपकी लागत होती है, यह एक try/exceptब्लॉक स्थापित करने के लिए लगभग मुफ्त है । लेकिन जब Exceptionवास्तव में होता है, तो लागत बहुत अधिक होती है।

नैतिक:

  • यह पूरी तरह से ठीक है (और "पायथोनिक") try/exceptप्रवाह नियंत्रण के लिए उपयोग करने के लिए,
  • लेकिन यह समझ में आता है जब Exceptionवास्तव में असाधारण हैं।

पायथन डॉक्स से:

EAFP

अनुमति की तुलना में क्षमा मांगना आसान है। यह सामान्य पायथन कोडिंग शैली वैध कुंजी या विशेषताओं के अस्तित्व को मानती है और यदि अपवाद गलत साबित होता है तो अपवादों को पकड़ता है। यह साफ और तेज शैली कई tryऔर exceptबयानों की उपस्थिति की विशेषता है । तकनीक LBYL शैली के साथ कई अन्य भाषाओं जैसे कि C के विपरीत है ।


1
धन्यवाद। मैं देखता हूं कि इस मामले में औचित्य परिणाम की उम्मीद हो सकती है।
21

6
.... और यह एक (कई कारणों में से) क्यों अजगर के लिए एक वास्तविक अनुकूलन JIT करना इतना कठिन है। के रूप में बीटा में हाल ही में LuaJIT 2 साबित होता है, गतिशील भाषाओं सकता है सच में, सच में तेजी से हो सकता है; लेकिन यह बहुत हद तक प्रारंभिक भाषा के डिजाइन और शैली को प्रोत्साहित करता है। (संबंधित नोट पर, भाषा डिजाइन यही कारण है कि बहुत अच्छे JavaScirpt JITs की तुलना LuaJIT 1, बहुत कम 2 से नहीं की जा सकती)
Javier

1
@ 2rs2ts: मैंने खुद भी ऐसी ही टाइमिंग की थी। पायथन 3 में, उन मामलों की try/exceptतुलना में 25% अधिक तेज था , if key in d:जहां कुंजी शब्दकोश में थी। यह बहुत धीमा था जब कुंजी शब्दकोश में नहीं थी, जैसा कि अपेक्षित था, और इस उत्तर के अनुरूप था।
टिम पिएत्केकर

5
मुझे पता है कि यह एक पुराना उत्तर है, हालांकि: 1/1समयसीमा जैसे बयानों का उपयोग करना एक बढ़िया विकल्प नहीं है, क्योंकि उन्हें बाहर अनुकूलित किया जाएगा (देखें dis.dis('1/1')और ध्यान दें कि कोई विभाजन नहीं होता है)।
एंड्रिया कोरबेलिनी

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

14

आपके फ़ंक्शन को मिश्रित प्रकार (यानी सूची या खाली स्ट्रिंग) नहीं लौटाना चाहिए। इसे मूल्यों की सूची या केवल एक खाली सूची वापस करनी चाहिए। फिर आपको किसी भी चीज़ के लिए परीक्षण करने की आवश्यकता नहीं होगी, अर्थात आपका कोड निम्न से ढह जाएगा:

for r in function():
    # process items

2
मैं पूरी तरह से उस बिंदु पर आपके साथ सहमत हूं; हालाँकि, फ़ंक्शन मेरा नहीं है, और मैं इसका उपयोग कर रहा हूं।
21

2
@artdanil: तो आप उस फ़ंक्शन को एक में लपेट सकते हैं जो आप लिखते हैं जो उस तरह काम करता है जैसा ब्रैंडन कॉर्फमैन सोच रहा है।
क्वांमरना

24
जो सवाल पूछता है: क्या रैपर को गैर-उपयोग करने योग्य मामले को संभालने की कोशिश करनी चाहिए या नहीं?
jcdyer

@quamrana जो वास्तव में मैं करने की कोशिश कर रहा हूं। जैसा कि @jcd ने बताया, सवाल यह है कि मुझे रैपर फ़ंक्शन की स्थिति को कैसे संभालना चाहिए।
20

12

कृपया मेरे समाधान को अनदेखा करें यदि मेरे द्वारा प्रदान किया गया कोड पहली नज़र में स्पष्ट नहीं है और आपको कोड नमूने के बाद स्पष्टीकरण को पढ़ना होगा।

क्या मैं मान सकता हूं कि "कोई मूल्य नहीं लौटाया" का अर्थ है कि वापसी मूल्य कोई भी नहीं है? यदि हाँ, या यदि "कोई मूल्य नहीं" गलत बूलियन-वार है, तो आप निम्न कार्य कर सकते हैं, क्योंकि आपका कोड अनिवार्य रूप से "नो वैल्यू" को "इटरेट नहीं" करता है:

for r in function() or ():
    # process items

यदि function()कुछ ऐसा है जो सत्य नहीं है, तो आप खाली टपल पर पुनरावृति करते हैं, अर्थात आप कोई पुनरावृत्तियों को नहीं चलाते हैं। यह अनिवार्य रूप से LBYL है।


4

आपका दूसरा उदाहरण टूट गया है - कोड कभी भी TypeError अपवाद को नहीं फेंकेगा क्योंकि आप स्ट्रिंग्स और सूचियों दोनों के माध्यम से पुनरावृति कर सकते हैं। खाली स्ट्रिंग या सूची के माध्यम से परिवर्तन करना भी मान्य है - यह लूप के शरीर को शून्य बार निष्पादित करेगा।


4

निम्नलिखित में से कौन अधिक बेहतर होगा और क्यों?

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

(हालांकि मैं ब्रैंडन कॉर्फमैन से सहमत हूं: खाली सूची के बजाय 'कोई आइटम नहीं' के लिए कोई भी नहीं लौटा है। यह जावा कोडर्स की एक अप्रिय आदत है जिसे पायथन में नहीं देखा जाना चाहिए। या जावा।)


4

आम तौर पर, मुझे जो धारणा मिली है वह यह है कि अपवाद असाधारण परिस्थितियों के लिए आरक्षित होना चाहिए। यदि resultउम्मीद की जाती है कि वह कभी भी खाली न हो (लेकिन हो सकता है, यदि, उदाहरण के लिए, एक डिस्क दुर्घटनाग्रस्त हो गया, आदि), तो दूसरा तरीका समझ में आता है। यदि, दूसरी ओर, एक खाली resultसामान्य परिस्थितियों में पूरी तरह से उचित है, तो एक ifबयान के साथ इसके लिए परीक्षण अधिक समझ में आता है।

मेरे मन में (अधिक सामान्य) परिदृश्य था:

# keep access counts for different files
file_counts={}
...
# got a filename somehow
if filename not in file_counts:
    file_counts[filename]=0
file_counts[filename]+=1

समकक्ष के बजाय:

...
try:
    file_counts[filename]+=1
except KeyError:
    file_counts[filename]=1

यह टिम पिएट्ज़कर के दृष्टिकोणों के बीच अंतर का एक उदाहरण है: पहला LBYL है, दूसरा EAFP है
Managu

बस एक त्वरित नोट जो ++अजगर में काम नहीं करता है, += 1इसके बजाय उपयोग करें ।
tgray 21

3

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

result = function();
try:
    it = iter(result)
except TypeError:
    pass
else:
    for r in it:
        #process items

जैसा कि आप देख सकते हैं, यह बल्कि बदसूरत है। मैं इसका सुझाव नहीं देता, लेकिन इसका उल्लेख पूर्णता के लिए किया जाना चाहिए।


मेरी नज़र में, जानबूझकर गलतियाँ करना, हमेशा खराब कोडिंग शैली है। एक डेवलपर को पता होना चाहिए कि अपवाद के बिना उस मूल्यों को संभालने के लिए क्या उम्मीद की जानी चाहिए और तैयार रहना चाहिए। जब भी कोई ऑपरेशन करता है तो उसे क्या करना चाहिए था (प्रोग्रामर के दृष्टिकोण से) और अपेक्षित परिणाम एक सूची है या None, हमेशा परिणाम के साथ जांचें is Noneया is not None। दूसरी तरफ वैध परिणामों के लिए अपवादों को बढ़ाने के लिए भी यह बुरी शैली है। अपवाद अप्रत्याशित चीजों के लिए हैं। उदाहरण: str.find()रिटर्न -1 यदि कुछ भी नहीं मिला है, क्योंकि खोज स्वयं त्रुटियों के बिना पूरी हुई।
बछसौ

1

जहां तक ​​प्रदर्शन का सवाल है, कोड के लिए कोशिश ब्लॉक का उपयोग करना जो सामान्य रूप से अपवाद नहीं उठाता है यदि स्टेटमेंट को हर बार उपयोग करने से तेज है। इसलिए, निर्णय एक्सटेंशनल मामलों की संभावना पर निर्भर करता है।


-5

अंगूठे के एक सामान्य नियम के रूप में, आपको प्रवाह को नियंत्रित करने के लिए कभी भी कोशिश / पकड़ या किसी भी अपवाद से निपटने वाले सामान का उपयोग नहीं करना चाहिए । भले ही पर्दे के पीछे से StopIterationअपवादों को उठाने के माध्यम से पुनरावृत्ति को नियंत्रित किया जाता है, फिर भी आपको अपने पहले कोड स्निपेट को दूसरे पर पसंद करना चाहिए।


7
यह जावा में सच है। पाइथन काफी भारी ईएएफपी को गले लगाता है।
fengb 21

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