पाइथन - 'इफ यू फू इन डिक्टेड' बनाम 'ट्राई: तानाशाह [फू]'


24

यह बतख टाइपिंग की प्रकृति के बारे में कम सवाल है और पायथोनिक रहने के बारे में अधिक है, मुझे लगता है।

सबसे पहले - जब डिट्स से निपटना, विशेष रूप से जब हुक की संरचना काफी अनुमानित है और दी गई कुंजी आम तौर पर मौजूद नहीं है, लेकिन कभी-कभी होती है, तो मैं पहले दो दृष्टिकोणों के बारे में सोचता हूं:

if myKey in dict:
    do_some_work(dict[myKey])
else:
    pass

और हां ये ओल्डे 'माफी बनाम अनुमति' दृष्टिकोण।

try:
    do_some_work(dict[myKey])
except KeyError:
    pass

एक यात्राकर्ता पायथन लड़के के रूप में, मुझे ऐसा लगता है कि मैं देख रहा हूं कि बाद वाले को बहुत पसंद किया गया है, जो केवल अजीब लगता है क्योंकि मुझे लगता है क्योंकि पायथन डॉक्स को try/exceptsलगता है कि जब कोई वास्तविक गलती होती है तो पसंद किया जाता है, एक उम के विपरीत ... सफलता की अनुपस्थिति?

अगर कभी-कभार तानाशाह के पास मेरे फैसले में चाबी नहीं है, और यह पता है कि यह हमेशा उस कुंजी के पास नहीं होगा, तो यह एक कोशिश है / संदर्भ को छोड़कर भ्रामक है? यह एक प्रोग्रामिंग त्रुटि नहीं है, यह डेटा का सिर्फ एक तथ्य है - यह तानाशाह के पास केवल उस विशेष कुंजी की आवश्यकता नहीं है।

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

try:
    foo += bar
except TypeError:
    pass
else:
    return some_more_work(foo)

क्या यह सभी प्रकार की अजीब त्रुटियों को निगलने के लिए नेतृत्व नहीं है जो शायद कुछ बुरे कोड का परिणाम है? उपरोक्त कोड आपको केवल यह देखने से रोक सकता है कि आप जोड़ने की कोशिश कर रहे हैं 2 + {}और आपको कभी भी यह महसूस नहीं हो सकता है कि आपके कोड का कुछ हिस्सा बुरी तरह से गलत हो गया है। मेरा सुझाव है कि हमें सभी प्रकारों की जांच करनी चाहिए, यही कारण है कि यह पायथन और जावास्क्रिप्ट नहीं है - लेकिन फिर से कोशिश / छोड़कर के संदर्भ के साथ, ऐसा लगता है कि यह प्रोग्राम को ऐसा करने के लिए पकड़ना चाहिए जो इसके बजाय ऐसा नहीं करना चाहिए। इसे आगे बढ़ाने में सक्षम बनाना।

मुझे लगता है कि उपरोक्त उदाहरण एक स्ट्रॉ-मैन तर्क का कुछ है, और वास्तव में जानबूझकर बुरा है। लेकिन मुझे दिया गया अजगर पंथ better to ask forgiveness than permissionमदद नहीं कर सकता है, लेकिन यह महसूस करता है कि यह सवाल उठता है कि रेत में रेखा वास्तव में कहां के सही अनुप्रयोग के बीच है / अन्यथा बनाम कोशिश / को छोड़कर, विशेष रूप से है, जब आप जानते हैं कि क्या होने की उम्मीद है वह डेटा जिसके साथ आप काम कर रहे हैं।

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

python 

मैं मानता हूं कि कोशिश को छोड़कर प्रवृत्ति त्रुटियों को छिपाने का जोखिम रखती है। मेरी राय यह है कि आपको आमतौर पर कोशिश को छोड़कर उन स्थितियों से बचना चाहिए जिनकी आप अपेक्षा करते हैं (बेशक कुछ अपवाद इस नियम पर लागू होते हैं)।
गॉर्डन बीन

जवाबों:


26

इसके बजाय प्राप्त विधि का उपयोग करें :

some_dict.get(the_key, default_value)

... default_valueयदि मान अंदर the_keyनहीं है, तो वापस कहाँ है some_dict। यदि आप छोड़ देते हैं default_value, Noneतो कुंजी गुम होने पर लौटा दी जाती है।

सामान्य तौर पर, पायथन में, लोग पहले कुछ जांचने के अलावा कोशिश करना पसंद करते हैं / करते हैं - शब्दकोष में ईएएफपी प्रविष्टि देखें । ध्यान दें कि कई "सदस्यता के लिए परीक्षण" कार्य पर्दे के पीछे अपवादों का उपयोग करते हैं।


हालांकि इस तरह की समस्या नहीं है? अगर हम dictजो मिला है, उसके आधार पर काम करने और काम करने की कोशिश कर रहे हैं , तो ऐसा लगता है कि if myDict.get(a_key) is not None: do_work(myDict[a_key])यह वर्डियर है और अभी तक छलांग लगाने से पहले निहितार्थ का एक और उदाहरण - प्लस यह थोड़ा कम पठनीय आईएमएचओ है। शायद मैं dict.get(a_key, a_default)सही संदर्भ में नहीं समझ पा रहा हूं , लेकिन ऐसा लगता है कि यह 'अग्र-स्विच-स्टेटमेंट अगर / elses' या जादुई मूल्यों को लिखने के लिए अग्रदूत है। मुझे यह पसंद है कि यह विधि क्या करती है, मैं इसे गहराई से देखता हूँ।

1
@ क्लिक - आप करते हैं: data = myDict.get(a_key, default)और या तो do_workसही काम करेंगे जब default(जैसे। None) या आप करते हैं if data: do_work(data)। दोनों मामलों में केवल एक ही खोज की आवश्यकता है। (यह हो सकता है if data is not None: ..., या तो मामले में, यह अभी भी केवल एक ही देखने और फिर अपने खुद के तर्क पर कब्जा कर सकते हैं।)
detly

1
इसलिए मैंने तय किया है कि मेरे मौजूदा प्रोजेक्ट में तानाशाही () ने मुझे बहुत सारे प्रयासों से बचाया है। इसने मेरी लाइन की संख्या को कम कर दिया है, बहुत सारे भयानक दिखने वाले try/except/elseकबाड़ को साफ कर दिया है और मेरे कोड की पठनीयता में सुधार किया है। मैंने एक मूल्यवान सबक सीखा है जो मैंने पहले सुना था लेकिन दिल से लेने की उपेक्षा करने में कामयाब रहा: "यदि आपको लगता है कि आप बहुत अधिक कोड लिख रहे हैं, तो रोकें और भाषा की विशेषताओं को देखें।" धन्यवाद!!

@Stick - यह सुनकर खुशी हुई :) मुझे वह सलाह पसंद है, मैंने पहले कभी नहीं सुना।
det

1
तकनीकी रूप से, कौन सा सबसे तेज है?
ओलिवियर पोंस

4

क्या मिसिंग एक नियम या एक अपवाद है ?

व्यावहारिक दृष्टिकोण से, फेंकना / पकड़ना बहुत धीमा होता है, फिर जाँचना कि कुंजी तालिका में है या नहीं। यदि गुम कुंजी एक सामान्य घटना है - आपको स्थिति का उपयोग करना चाहिए।

हालत के पक्ष में एक और बात एक और खंड है - यह समझने में बहुत आसान है कि जब या तो ब्लॉक किया जाता है, तो विचार करें कि एक ही अपवाद वर्ग को कोशिश ब्लॉक में कई बयानों से फेंक दिया जा सकता है।

क्लॉज को छोड़कर कोड सामान्य दोष का हिस्सा नहीं होना चाहिए (जैसे कि यदि कुंजी नहीं है, तो इसे जोड़ें) - यह त्रुटि को संभालना चाहिए।


4
"व्यावहारिक दृष्टिकोण से, फेंकना / पकड़ना बहुत धीमा है, फिर जाँचना कि कुंजी टेबल में है या नहीं" - नहीं। जरूरी नहीं, वैसे भी। पिछले मैंने जाँच की, सबसे आम पायथन कार्यान्वयन try/ catchसंस्करण तेजी से करते हैं।
detly

2
अजगर में फेंक / पकड़ सौदा प्रदर्शन के सभी बड़े नहीं है, इस हद तक कि यह अक्सर अजगर में प्रवाह-नियंत्रण के लिए उपयोग किया जाता है। इसके अतिरिक्त, कुछ स्थितियों में संभावना है कि परीक्षण और पहुंच के बीच उस तानाशाही को संशोधित किया जा सकता है।
whatsisname

@whatsisname - मैंने इसे अपने उत्तर में शामिल करने के बारे में सोचा, लेकिन टीबीएच अगर आपके पास दौड़ के खतरे हैं, तो आपके पास बहुत बड़ी समस्याएं हैं जो ईएएफपी बनाम एलबीवाईएल: पी
डेटली

1

"पायथोनिक" होने की भावना में और, विशेष रूप से, बतख टाइपिंग - कोशिश / छोड़कर मुझे लगभग नाजुक लगती है।

आप वास्तव में चाहते हैं कि कुछ तानाशाही जैसी पहुंच के साथ हो, लेकिन __getitem__कुछ ऐसा करने के लिए ओवरराइड किया जा सकता है जैसा कि आप उम्मीद करते हैं। उदाहरण के लिए, defaultdictमानक पुस्तकालय से उपयोग करना :

In [1]: from collections import defaultdict

In [2]: foo = defaultdict(int)

In [3]: foo['a'] = 1

In [4]: foo['b']  # Someone did access checking with a try/except exactly as you have in the question
Out[4]: 0

In [5]: 'a' in foo
Out[5]: True

In [6]: 'b' in foo  # We never set it, but now it exists!
Out[6]: True

In [7]: 'c' in foo
Out[7]: False

क्योंकि डिफ़ॉल्ट रिटर्न वैल्यू फाल्सी है, ऐसे में एक्सेस चेकिंग ज्यादातर समय ठीक काम करेगी .. यह कोड को सरल रखने के लिए प्रतीत होता है, यही कारण है कि मेरे सहकर्मियों और मैंने इसे महीनों तक किया था।

दुर्भाग्य से, कुछ महीनों बाद, इन अतिरिक्त कुंजियों ने वास्तव में समस्याओं और हार्ड-टू-ट्रैक डाउन बग को समाप्त कर दिया, क्योंकि 0एक वैध मूल्य बन गया। और कभी-कभी हम यहin जांचने के लिए उपयोग करते हैं कि क्या कोई कुंजी मौजूद है, जिससे कोड अलग-अलग काम करता है जब यह समान होना चाहिए था।

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

, पहले संस्करण का उपयोग करें if myKey in mydict


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

  • एक दौड़ की स्थिति यह है कि फ़ाइल को हटा दिया गया / स्थानांतरित किया जा सकता है / आदि
  • आपके पास फ़ाइल पर अनुमतियाँ नहीं हैं
  • फ़ाइल दूषित हो गई है

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

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