`अगर कुंजी में प्रमुख` बनाम `कोशिश / को छोड़कर` - जो अधिक पठनीय मुहावरा है?


93

मेरे पास मुहावरों और पठनीयता के बारे में एक प्रश्न है, और इस विशेष मामले के लिए पायथन दर्शन का एक टकराव प्रतीत होता है:

मैं शब्दकोश बी से शब्दकोश बनाना चाहता हूं यदि बी में एक विशिष्ट कुंजी मौजूद नहीं है, तो कुछ भी न करें और जारी रखें।

कौन सा तरीका बेहतर है?

try:
    A["blah"] = B["blah"]
except KeyError:
    pass

या

if "blah" in B:
    A["blah"] = B["blah"]

"करो और माफ़ी मांगो" बनाम "सादगी और खोजकर्ता"।

कौन सा बेहतर है और क्यों है?


1
दूसरा उदाहरण बेहतर लिखा जा सकता है if "blah" in B.keys(), या if B.has_key("blah")
girasquid

2
A.update(B)आपके लिए काम नहीं करता है ?
साइलेंटगॉस्ट

21
@ ल्यूक: एक O (n) एक में O (1) ऑपरेशन में परिवर्तन और जाँच के has_keyपक्ष में पदावनत किया गया है । inB.keys()
किंडल

4
@ ल्यूक: ऐसा नहीं है। .has_keyपदावनत है और keyspy2k में अनावश्यक सूची बनाता है, और py3k में निरर्थक है
साइलेंटगॉस्ट

2
'निर्माण' ए, के रूप में, ए के साथ शुरू करने के लिए खाली है? और हम केवल कुछ चाबियाँ चाहते हैं? एक समझ का उपयोग करें A = dict((k, v) for (k, v) in B if we_want_to_include(k)):।
कार्ल केनचेल

जवाबों:


76

अपवाद सशर्त नहीं हैं।

सशर्त संस्करण स्पष्ट है। यह स्वाभाविक है: यह सीधा प्रवाह नियंत्रण है, जो कि सशर्त के लिए डिज़ाइन किया गया है, अपवाद नहीं है।

अपवाद संस्करण मुख्य रूप से एक लूप में इन लुकअप को करते समय अनुकूलन के रूप में उपयोग किया जाता है: कुछ एल्गोरिदम के लिए यह आंतरिक छोरों से परीक्षण को समाप्त करने की अनुमति देता है। यहाँ वह लाभ नहीं है। इसका छोटा फायदा है कि यह "blah"दो बार कहने से बचता है , लेकिन अगर आप इनमें से बहुत कुछ कर रहे हैं, तो आपको शायद move_keyवैसे भी एक सहायक कार्य करना चाहिए ।

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


3
मैं सहमत नहीं हूँ। यदि आप कहते हैं "X करें, और यदि वह काम नहीं करता है, तो Y करें"। यहां सशर्त समाधान के खिलाफ मुख्य कारण, आपको "blah"अधिक बार लिखना होगा , जिससे अधिक त्रुटि-ग्रस्त स्थिति हो सकती है।
8

6
और, मुख्य रूप से पायथन में, ईएएफपी बहुत व्यापक रूप से उपयोग किया जाता है।
8

8
यह उत्तर किसी भी भाषा के लिए सही होगा जिसे मैं पायथन को छोड़कर जानता हूं।
टॉम ज़ातो -

3
यदि आप अपवादों का उपयोग कर रहे हैं जैसे कि वे पायथन में सशर्त हैं, तो मुझे आशा है कि किसी और को इसे पढ़ना नहीं होगा।
ग्लेन मेनार्ड

तो, अंतिम फैसला क्या है? :)
floatingpurr

60

एक तीसरा तरीका भी है जो अपवादों और दोहरे-लुकअप दोनों से बचता है, जो लुकअप महंगा होने पर महत्वपूर्ण हो सकता है:

value = B.get("blah", None)
if value is not None: 
    A["blah"] = value

यदि आप शब्दकोश में Noneमूल्यों को शामिल करने की अपेक्षा करते हैं, तो आप कुछ अधिक गूढ़ स्थिरांक का उपयोग कर सकते हैं NotImplemented, Ellipsisया एक नया बना सकते हैं:

MyConst = object()
def update_key(A, B, key):
    value = B.get(key, MyConst)
    if value is not MyConst: 
        A[key] = value

वैसे भी, उपयोग update()करना मेरे लिए सबसे पठनीय विकल्प है:

a.update((k, b[k]) for k in ("foo", "bar", "blah") if k in b)

14

जो मैं समझता हूं, आप तानाशाह ए से कुंजी बी के मूल्य वाले जोड़े को अपडेट करना चाहते हैं

update एक बेहतर विकल्प है।

A.update(B)

उदाहरण:

>>> A = {'a':1, 'b': 2, 'c':3}
>>> B = {'d': 2, 'b':5, 'c': 4}
>>> A.update(B)
>>> A
{'a': 1, 'c': 4, 'b': 5, 'd': 2}
>>> 

"यदि बी में एक विशिष्ट कुंजी मौजूद नहीं है" क्षमा करें, अधिक स्पष्ट होना चाहिए था, लेकिन मैं केवल उन मूल्यों पर प्रतिलिपि बनाना चाहता हूं यदि बी में विशिष्ट कुंजी मौजूद है। बी में सभी नहीं
लीमोबाइल

1
@LeeMobile -A.update({k: v for k, v in B.iteritems() if k in specificset})
ओमनीफेरियस

8

अजगर प्रदर्शन विकि से प्रत्यक्ष उद्धरण:

पहली बार को छोड़कर, यदि कथन के परीक्षण में विफल होने पर हर बार किसी शब्द को देखा जाता है। यदि आप बड़ी संख्या में शब्दों की गिनती कर रहे हैं, तो कई संभवतः कई बार होंगे। ऐसी स्थिति में जहाँ किसी मूल्य का आरंभीकरण केवल एक बार होने वाला है और उस मूल्य का संवर्द्धन कई बार होगा जब एक कोशिश कथन का उपयोग करना सस्ता होगा।

तो ऐसा लगता है कि दोनों विकल्प स्थिति के आधार पर व्यवहार्य हैं। अधिक जानकारी के लिए आप इस लिंक को देखना चाहेंगे: कोशिश-अपवाद-प्रदर्शन


यह एक दिलचस्प पढ़ा है, लेकिन मुझे लगता है कि कुछ अधूरा है। केवल इस्तेमाल किए जाने वाले
तानाशाह

3

मुझे लगता है कि यहां सामान्य नियम सामान्य A["blah"]रूप से मौजूद होगा , यदि ऐसा नहीं है तो कोशिश करना-छोड़ना अच्छा हैif "blah" in b:

मुझे लगता है कि "कोशिश" समय में सस्ता है लेकिन "को छोड़कर" अधिक महंगा है।


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

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

3

मुझे लगता है कि दूसरा उदाहरण आपको तब तक के लिए जाना चाहिए जब तक कि यह कोड समझ में न आए:

try:
    A["foo"] = B["foo"]
    A["bar"] = B["bar"]
    A["baz"] = B["baz"]
except KeyError:
    pass

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

बेशक, आपको बताने वाले लोग updateसही हैं। यदि आप पायथन के एक संस्करण का उपयोग कर रहे हैं जो शब्दकोश समझ का समर्थन करता है, तो मैं दृढ़ता से इस कोड को पसंद करूंगा:

updateset = {'foo', 'bar', 'baz'}
A.update({k: B[k] for k in updateset if k in B})

"ध्यान रखें कि जैसे ही कोई कुंजी बी में नहीं होगी, कोड खत्म हो जाएगा" - यही कारण है कि कोशिश में केवल न्यूनतम पूर्ण डालने के लिए सबसे अच्छा अभ्यास है: ब्लॉक, आमतौर पर यह एक एकल पंक्ति है। पहला उदाहरण एक लूप के हिस्से के रूप में बेहतर होगा, जैसे किfor key in ["foo", "bar", "baz"]: try: A[key] = B[key]
Zim

2

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


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

@JohnLaRooy नहीं, प्रदर्शन वास्तव में कारण नहीं है। अपवाद एक तरह का गैर-स्थानीय गोटो है , जिसे कुछ लोग कोड की पठनीयता को बाधित करने के लिए मानते हैं। हालाँकि, इस तरह से अपवादों का उपयोग पायथन में मुहावरेदार माना जाता है, इसलिए उपरोक्त लागू नहीं होता है।
इयान गोल्डी

सशर्त रिटर्न भी "गैर-स्थानीय गोटो" हैं और बहुत से लोग कोड ब्लॉक के अंत में प्रहरी का निरीक्षण करने के बजाय उस शैली को पसंद करते हैं।
काउबर्ट

1

व्यक्तिगत रूप से, मैं दूसरी विधि की ओर झुकता हूं (लेकिन उपयोग करके has_key):

if B.has_key("blah"):
  A["blah"] = B["blah"]

इस तरह, प्रत्येक असाइनमेंट ऑपरेशन केवल दो लाइनें हैं (4 के बजाय / कोशिश के अलावा), और फेंक दिया गया कोई भी अपवाद वास्तविक त्रुटियां या चीजें हैं जो आप चूक गए हैं (केवल वहां पहुंचने की कुंजी का उपयोग करने की कोशिश के बजाय) ।

जैसा कि यह निकला (आपके प्रश्न पर टिप्पणी देखें), has_keyपदावनत किया गया है - इसलिए मुझे लगता है कि यह बेहतर लिखा गया है

if "blah" in B:
  A["blah"] = B["blah"]

1

प्रारंभ करना Python 3.8, और असाइनमेंट एक्सप्रेशन (पीईपी 572) ( :=ऑपरेटर) की शुरूआत , हम दोनों को चेक करने के लिए dictB.get('hello', None)एक चर valueमें शर्त मान को पकड़ सकते हैं यदि यह नहीं है None(जैसा dict.get('hello', None)कि संबंधित मूल्य या तो रिटर्न None) या फिर इसका उपयोग शरीर के भीतर करें। शर्त:

# dictB = {'hello': 5, 'world': 42}
# dictA = {}
if value := dictB.get('hello', None):
  dictA["hello"] = value
# dictA is now {'hello': 5}

यह विफल रहता है अगर मान == 0
एरिक

0

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

अनुमति की तुलना में क्षमा मांगना आसान है। (EAFP)

यहां अजगर डॉक्स संदर्भ देखें ।

इसके अलावा, ब्रेट का यह ब्लॉग , जो कोर देवों में से एक है, इसे संक्षेप में सबसे अधिक छूता है।

एक और SO चर्चा यहाँ देखें :

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