पाइथोनिक तरीके से बचने के लिए "यदि एक्स: रिटर्न एक्स" कथन


218

मेरे पास एक विधि है जो विशिष्ट परिस्थितियों की जांच के लिए 4 अन्य तरीकों को कॉल करती है, और जब भी कोई व्यक्ति सत्यता लौटाता है, तो तुरंत वापस लौटता है (निम्नलिखित लोगों की जांच नहीं करता है)।

def check_all_conditions():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

यह बहुत सारे सामान कोड जैसा लगता है। कथन के अनुसार प्रत्येक 2-पंक्ति के बजाय, मैं कुछ ऐसा करूंगा:

x and return x

लेकिन वह अमान्य पायथन है। क्या मुझे यहाँ एक सरल, सुरुचिपूर्ण समाधान याद आ रहा है? संयोग से, इस स्थिति में, वे चार चेक तरीके महंगे हो सकते हैं, इसलिए मैं उन्हें कई बार कॉल नहीं करना चाहता।


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

13
@gerrit कोड जैसा कि ऊपर प्रस्तुत काल्पनिक / छद्म कोड है जो कोड समीक्षा पर ऑफ-टॉपिक है। यदि पोस्ट के लेखक अपने वास्तविक, वास्तविक कार्य कोड की समीक्षा करना चाहते हैं, तो हाँ कोड समीक्षा पर पोस्ट करने के लिए उनका स्वागत है।
फ्राँसिस

4
आपको क्यों लगता x and return xहै कि बेहतर है if x: return x? उत्तरार्द्ध कहीं अधिक पठनीय है और इस प्रकार बनाए रखने योग्य है। आपको वर्णों या रेखाओं की संख्या के बारे में बहुत अधिक चिंता नहीं करनी चाहिए; पठनीयता मायने रखती है। वे वैसे भी गैर-व्हॉट्सएप वर्णों की सटीक समान संख्या हैं, और यदि आपको वास्तव में चाहिए, if x: return xतो बस एक लाइन पर ठीक काम करेगा।
13 दिसंबर को मार्सेलम

3
कृपया स्पष्ट करें कि क्या आप वास्तविक मूल्यों की परवाह करते हैं या आपको वास्तव में सिर्फ एक बूलियन वापस करने की आवश्यकता है। इससे एक फर्क पड़ता है कि कौन से विकल्प उपलब्ध हैं और यह भी कि कौन अधिक स्पष्ट रूप से इरादे का संचार करता है। नामकरण आपको केवल एक बूलियन की आवश्यकता है। यह भी एक फर्क पड़ता है कि इन कार्यों के लिए कई कॉल से बचना महत्वपूर्ण है या नहीं। यदि फ़ंक्शंस पैरामीटर के किसी भी या अलग-अलग सेट लेते हैं, तो यह भी बात कर सकता है। इन स्पष्टीकरणों के बिना, मुझे लगता है कि यह प्रश्न अस्पष्ट, बहुत व्यापक, या राय आधारित में से एक में आता है।
jpmc26

7
@ jpmc26 ओपी स्पष्ट रूप से सत्य रिटर्न मानों की बात करता है, और फिर उसका कोड रिटर्न x(जैसा विरोध किया जाता है bool(x)), क्योंकि यह खड़ा है मुझे लगता है कि यह मान लेना सुरक्षित है कि ओपी के कार्य कुछ भी वापस कर सकते हैं, और वह पहला कुछ भी चाहता है जो सत्य है।
टाइमजैब

जवाबों:


278

आप एक लूप का उपयोग कर सकते हैं:

conditions = (check_size, check_color, check_tone, check_flavor)
for condition in conditions:
    result = condition()
    if result:
        return result

इसका अतिरिक्त लाभ यह है कि अब आप शर्तों की संख्या को परिवर्तनशील बना सकते हैं।

आप पहले ऐसे मिलान मूल्य प्राप्त करने के लिए map()+ filter()(पायथन 3 संस्करणों का उपयोग कर सकते future_builtinsहैं , पायथन 2 में संस्करणों का उपयोग कर सकते हैं ):

try:
    # Python 2
    from future_builtins import map, filter
except ImportError:
    # Python 3
    pass

conditions = (check_size, check_color, check_tone, check_flavor)
return next(filter(None, map(lambda f: f(), conditions)), None)

लेकिन अगर यह अधिक पठनीय है तो बहस करने योग्य है।

एक अन्य विकल्प जनरेटर अभिव्यक्ति का उपयोग करना है:

conditions = (check_size, check_color, check_tone, check_flavor)
checks = (condition() for condition in conditions)
return next((check for check in checks if check), None)

27
यदि स्थितियां वास्तव में केवल स्थितियां हैं, अर्थात बूलियन तो आपके पहले प्रस्ताव में आप anyलूप के बजाय बिलिन का उपयोग कर सकते हैं । return any(condition() for condition in conditions)

4
@ लियोनहार्ड: के anyअंदर लगभग समान कार्यान्वयन है। लेकिन यह बहुत बेहतर लग रहा है, कृपया इसे उत्तर के रूप में पोस्ट करें)
निक वोल्किन

13
पठनीयता लगभग सभी अन्य विचारों को प्रभावित करती है। आप कहते हैं, मानचित्र / फ़िल्टर 'डिबेटेबल' है, मैंने अपना वोट निर्विवाद रूप से बदसूरत के लिए डाला। धन्यवाद, निश्चित रूप से, लेकिन अगर मेरी टीम में किसी ने इस कोड के लिए एक नक्शा / फ़िल्टर डाला है तो मैं उन्हें दूसरी टीम में स्थानांतरित कर दूंगा या उन्हें बेडपेन ड्यूटी पर सौंप दूंगा।
केविन जे। राइस

15
क्या कोड का यह अपठनीय ब्लॉक वास्तव में "पायथोनियन" है? और विशेष रूप से ज़िपिंग का विचार conditionsऔर arguments? यह IMHO मूल कोड से बहुत खराब है, जो मेरे ब्रेनपर्स द्वारा पार्स करने में लगभग 10 सेकंड लेता है।
यो '

34
"पाइथन को प्राथमिकता दें", उन्होंने कहा। "पर्ल अप्राप्य है", उन्होंने कहा। और फिर यह हुआ return next((check for check in checks if check), None):।
जजा

393

वैकल्पिक रूप से मार्टिज़न के ठीक जवाब के लिए, आप चेन कर सकते हैं or। यह पहला सत्य मूल्य लौटाएगा, या Noneयदि कोई सत्य मूल्य नहीं है:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor() or None

डेमो:

>>> x = [] or 0 or {} or -1 or None
>>> x
-1
>>> x = [] or 0 or {} or '' or None
>>> x is None
True

9
यकीन है, लेकिन यह तेजी से पढ़ने के लिए कठिन हो जाएगा अगर कुछ विकल्प से अधिक हैं। इसके अलावा मेरा दृष्टिकोण आपको एक चर संख्या का उपयोग करने देता है।
मार्टिन पीटर्स

14
@MartijnPieters आप \प्रत्येक चेक को अपनी लाइन में लगाने के लिए उपयोग कर सकते हैं ।
कारिडोरक

12
@MartijnPieters मैंने कभी नहीं सोचा कि मेरा उत्तर आपके मुकाबले बेहतर है, मुझे आपका जवाब पसंद है, :)
टाइमजैब

38
@ कारिडोरक: मैं \तार्किक रेखा का विस्तार करने के लिए दृढ़ता से नापसंद करता हूं। जहाँ संभव हो, कोष्ठक का प्रयोग करें; इसलिए return (....)जरूरत पड़ने पर नए सिरे से डाले गए। फिर भी, यह एक लंबी तार्किक रेखा होगी।
मार्टिन पीटर्स

47
मुझे लगता है कि यह बेहतर उपाय है। तर्क "यह थकाऊ हो जाएगा [..] अगर कुछ विकल्प से अधिक हैं" तो लूट है, क्योंकि एक भी फ़ंक्शन किसी भी तरह से चेक की एक अत्यधिक संख्या में नहीं होना चाहिए। यदि यह आवश्यक है, तो चेक को कई कार्यों में विभाजित किया जाना चाहिए।
ब्लूराजा - डैनी पफ्लुगुएफ़ट

88

इसे मत बदलो

ऐसा करने के अन्य तरीके हैं जैसे कि अन्य अन्य उत्तर दिखाते हैं। कोई भी आपके मूल कोड जितना स्पष्ट नहीं है।


39
मैं इसके खिलाफ तर्क दूंगा, लेकिन आपके सुझाव को वाजिब माना जा सकता है। व्यक्तिगत रूप से, मुझे लगता है कि मेरी आंखें ओपी को पढ़ने की कोशिश कर रही हैं, उदाहरण के लिए, टाइमगैब के समाधान तुरंत क्लिक करता है।
11:43 पर रीति 43

3
यह वास्तव में एक राय की बात है। मुझे व्यक्तिगत रूप से, मैं बाद में नए सिरे से हटा दूंगा :, क्योंकि मैं if x: return xबहुत ठीक समझता हूं , और यह फ़ंक्शन को अधिक कॉम्पैक्ट बनाता है। लेकिन वह सिर्फ मैं ही हो सकता हूं।
यो '

2
यह सिर्फ आप नहीं है। orटाइमजेब के रूप में उपयोग करना एक उचित और अच्छी तरह से समझा गया मुहावरा है। कई भाषाओं में यह है; शायद जब इसे कहा जाता है तो orelseयह और भी अधिक स्पष्ट होता है, लेकिन यहां तक ​​कि सादे पुराने or(या ||अन्य भाषाओं में) का मतलब यह समझने के विकल्प के रूप में समझा जाता है कि अगर पहले वाला "काम नहीं करता है।"
रे तोल

1
@RayToal: अन्य भाषाओं के मुहावरों को आयात करना कोड को बाधित करने का एक शानदार तरीका है।
जैक ऐडली

1
कभी-कभी हां, निश्चित रूप से! इसके अलावा यह किसी के दिमाग को खोलने और नए और बेहतर पैटर्न और प्रतिमानों की खोज करने का एक तरीका हो सकता है, जिसे पहले किसी ने कोशिश नहीं की होगी। शैली उधार लेने और साझा करने और नई चीजों की कोशिश करने वाले लोगों द्वारा विकसित होती है। दोनों तरह से काम करता है। वैसे भी, मैंने कभी भी orअन-पायथोनिक लेबल का इस्तेमाल नहीं किया है या किसी भी तरह से बाधा नहीं डाली है, लेकिन यह वैसे भी एक राय है --- जैसा कि यह होना चाहिए।
रे तोल

83

प्रभावी रूप से टाइमगैब के रूप में एक ही जवाब है, लेकिन आप अच्छे फॉर्मेटिंग के लिए कोष्ठक का उपयोग कर सकते हैं:

def check_all_the_things():
    return (
        one()
        or two()
        or five()
        or three()
        or None
    )

8
हर कोई 1 जगह तक इस जवाब को बढ़ाने में मदद करें। क्या तुम हिस्सा हो !
गयोम

74

के अनुसार घुंघराले के नियम , तो आप इस कोड अधिक बंटवारे दो चिंताओं द्वारा पठनीय बना सकते हैं:

  • मैं किन चीजों की जांच करूं?
  • क्या एक बात सच हुई है?

दो कार्यों में:

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions():
    for condition in all_conditions():
        if condition:
            return condition
    return None

इससे बचा जाता है:

  • जटिल तार्किक संरचनाएं
  • वास्तव में लंबी लाइनें
  • दुहराव

... जबकि एक रेखीय संरक्षण, प्रवाह को पढ़ने के लिए आसान।

आप शायद अपने विशेष परिस्थितियों के अनुसार, बेहतर फ़ंक्शन नामों के साथ भी आ सकते हैं, जो इसे और भी पठनीय बनाते हैं।


मुझे यह पसंद है, हालांकि सच / गलत को हालत में बदलना चाहिए / सवाल का मिलान करने के लिए कोई नहीं।
मैल्कम

2
यह मेरा पसंदीदा है! यह विभिन्न जांचों और तर्कों के साथ भी मुकाबला करता है। काफी संभवतः इस विशेष उदाहरण के लिए अतिदेय लेकिन भविष्य की समस्याओं के लिए एक बहुत उपयोगी उपकरण!
rjh

4
ध्यान दें कि return Noneआवश्यक नहीं है, क्योंकि फ़ंक्शन Noneडिफ़ॉल्ट रूप से लौटते हैं । हालाँकि, Noneस्पष्ट रूप से लौटने में कुछ भी गलत नहीं है , और मुझे पसंद है कि आपने ऐसा करने के लिए चुना।
टाइमजैब

1
मुझे लगता है कि इस दृष्टिकोण को स्थानीय फ़ंक्शन परिभाषा के साथ बेहतर तरीके से लागू किया जाएगा।
जैक आइडली

1
@timgeb "स्पष्ट रूप से निहित से बेहतर है," पायथन का ज़ेन
jpmc26

42

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

लूप के बजाय आप बिलिन का उपयोग कर सकते हैं any

conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions) 

ध्यान दें कि anyएक बूलियन लौटाता है, इसलिए यदि आपको चेक के सटीक वापसी मूल्य की आवश्यकता है, तो यह समाधान काम नहीं करेगा। anyके बीच भेद नहीं होगा 14, 'red', 'sharp', 'spicy'वापसी मान के रूप में, वे सब के रूप में लौटा दी जाएगी True


आप next(itertools.ifilter(None, (c() for c in conditions)))इसे बूलियन में डाले बिना वास्तविक मूल्य प्राप्त कर सकते हैं ।
कोजिरो

1
क्या anyवास्तव में शॉर्ट-सर्किट होता है?
zwol

1
@zwol हाँ कुछ नमूना कार्यों के साथ इसे आज़माएं या docs.python.org/3/library/functions.html

1
यह 'या' के साथ 4 कार्यों का पीछा करने से कम पठनीय है और केवल तभी भुगतान करता है जब शर्तों की संख्या बड़ी या गतिशील हो।
rjh

1
@rjh यह पूरी तरह से पठनीय है; यह सिर्फ एक सूची शाब्दिक और एक समझ है। मैं इसे पसंद करूंगा क्योंकि मेरी आंखें तीसरे के बारे में ग्लैज़ेथ पर हैंx = bar(); if x: return x;
ब्लैकलाइट शाइनिंग

27

क्या आपने सिर्फ if x: return xएक लाइन पर सब लिखने पर विचार किया है ?

def check_all_conditions():
    x = check_size()
    if x: return x

    x = check_color()
    if x: return x

    x = check_tone()
    if x: return x

    x = check_flavor()
    if x: return x

    return None

यह आपके द्वारा की गई तुलना में किसी भी दोहराव से कम नहीं है , लेकिन IMNSHO यह बहुत थोड़ा चिकनी पढ़ता है।


24

मैं काफी हैरान हूं कि किसी ने anyइस उद्देश्य के लिए बिल्ट-इन का उल्लेख नहीं किया है :

def check_all_conditions():
    return any([
        check_size(),
        check_color(),
        check_tone(),
        check_flavor()
    ])

ध्यान दें कि हालांकि यह कार्यान्वयन संभवतः सबसे स्पष्ट है, यह सभी जांचों का मूल्यांकन करता है, भले ही पहले वाला हो True


यदि आपको वास्तव में पहले विफल चेक पर रुकने की आवश्यकता है, तो उस सूची पर विचार करें reduceजिसका उपयोग किसी सूची को सरल मान में करने के लिए किया जाता है:

def check_all_conditions():
    checks = [check_size, check_color, check_tone, check_flavor]
    return reduce(lambda a, f: a or f(), checks, False)

reduce(function, iterable[, initializer]): दो तर्कों के फ़ंक्शन को संचयी रूप से पुनरावृत्त की वस्तुओं पर लागू करें, बाएं से दाएं, ताकि एक मान के लिए पुनरावृत्त को कम किया जा सके। बाएँ तर्क, x, संचित मूल्य है और सही तर्क, y, चलने योग्य से अद्यतन मान है। यदि वैकल्पिक आरंभीकरण मौजूद है, तो इसे गणना में चलने योग्य वस्तुओं से पहले रखा जाता है

आपके मामले में:

  • lambda a, f: a or f()वह कार्य है जो जाँचता है कि या तो संचायक aया वर्तमान जाँच f()है True। ध्यान दें कि यदि aहै True, तो f()मूल्यांकन नहीं किया जाएगा।
  • checksजाँच कार्य ( fलंबोदर से आइटम) शामिल हैं
  • False प्रारंभिक मूल्य है, अन्यथा कोई जाँच नहीं होगी और परिणाम हमेशा रहेगा True

anyऔर reduceकार्यात्मक प्रोग्रामिंग के लिए बुनियादी उपकरण हैं। मैं दृढ़ता से आपको इनको प्रशिक्षित करने के लिए प्रोत्साहित करता हूं और साथ ही साथ mapयह बहुत बढ़िया भी है!


9
anyकेवल तभी काम करता है जब चेक वास्तव में बूलियन मान लौटाते हैं, शाब्दिक रूप से Trueया False, लेकिन यह प्रश्न निर्दिष्ट नहीं करता है। आपको reduceचेक द्वारा लौटाए गए वास्तविक मूल्य को वापस करने के लिए उपयोग करने की आवश्यकता होगी । इसके अलावा, anyजनरेटर का उपयोग करके सभी जांचों का मूल्यांकन करने से बचना काफी आसान है , जैसे any(c() for c in (check_size, check_color, check_tone, check_flavor))। जैसा कि लियोनहार्ड के जवाब में
डेविड जेड

मुझे आपका स्पष्टीकरण और उपयोग पसंद है reduce। @DavidZ की तरह, मेरा मानना ​​है कि आपके समाधान के साथ anyएक जनरेटर का उपयोग करना चाहिए और यह इंगित करने की आवश्यकता है कि यह वापस लौटने तक सीमित है Trueया False
टाइमजैब

1
@ डेविड वास्तव में सत्य anyमूल्यों के साथ काम करता है: any([1, "abc", False]) == Trueऔरany(["", 0]) == False
13:22

3
@ मुझे खेद है, मैं स्पष्ट नहीं था। प्रश्न का लक्ष्य चेक के परिणाम को वापस करना है (और न केवल यह इंगित करना है कि चेक सफल हुआ या विफल)। मैं इंगित कर रहा था कि anyकेवल उस उद्देश्य के लिए काम करता है यदि चेक चेक से वास्तविक बूलियन मान लौटाए जाते हैं।
डेविड जेड

19

यदि आप समान कोड संरचना चाहते हैं, तो आप टर्नरी स्टेटमेंट का उपयोग कर सकते हैं!

def check_all_conditions():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

मुझे लगता है कि अगर आप इसे देखते हैं तो यह अच्छा और स्पष्ट दिखता है।

डेमो:

इसका स्क्रीनशॉट चल रहा है


7
अपने टर्मिनल के ऊपर छोटी ASCII मछली के साथ Whats?

36
@LegoStormtroopr मैं मछली के खोल का उपयोग करता हूं, इसलिए मुझे खुश करने के लिए इसे एक एस्सी मछली टैंक के साथ सजाता हूं। :)
फ़िनेट

3
ठीक मछली के लिए धन्यवाद (और जिस तरह से रंग, संपादक क्या है?)
मैथ्यूडलर

4
आप fishshell.com पर मछली पा सकते हैं , और ascii के लिए config फाइल यहाँ pastebin.com/yYVYvVeK , संपादक भी उदात्त पाठ है।
फिनीट

9
x if x else <something>बस कम किया जा सकता हैx or <something>

5

मेरे लिए, सबसे अच्छा जवाब यह है कि @ फिल-फ्रॉस्ट से, इसके बाद @ वेन-वर्नर।

मुझे जो दिलचस्प लगता है वह यह है कि किसी ने इस तथ्य के बारे में कुछ नहीं कहा है कि एक फ़ंक्शन कई अलग-अलग डेटा प्रकार लौटाएगा, जो किसी भी आगे के काम को करने के लिए x के प्रकार पर चेक करना अनिवार्य कर देगा।

इसलिए मैं एक प्रकार के विचार रखने के साथ @ फिलफ्रॉस्ट की प्रतिक्रिया को मिलाऊंगा:

def all_conditions(x):
    yield check_size(x)
    yield check_color(x)
    yield check_tone(x)
    yield check_flavor(x)

def assessed_x(x,func=all_conditions):
    for condition in func(x):
        if condition:
            return x
    return None

नोटिस जो xएक तर्क के रूप में पारित किया जाता है, लेकिन all_conditionsचेकिंग फ़ंक्शन के पारित जनरेटर के रूप में भी उपयोग किया जाता है जहां सभी को xचेक किया जाना है, और वापस Trueया False। का उपयोग करके funcके साथ all_conditionsके रूप में डिफ़ॉल्ट मान है, तो आप उपयोग कर सकते हैं assessed_x(x), या आप के माध्यम से एक और व्यक्तिगत जनरेटर पारित कर सकते हैं func

इस तरह, आप xजैसे ही एक चेक पास करते हैं, लेकिन यह हमेशा एक ही प्रकार का होगा।


4

आदर्श रूप में, मैं मान के बजाय check_ वापस लौटने के लिए Trueया फिर से लिखने के कार्यों को लिखूंगा False। आपके चेक तो बन जाते हैं

if check_size(x):
    return x
#etc

यह मानते हुए कि आपका xकार्य अपरिवर्तनीय नहीं है, फिर भी आपका फ़ंक्शन इसे संशोधित कर सकता है (हालाँकि वे इसे पुन: असाइन नहीं कर सकते) - लेकिन एक फ़ंक्शन जिसे checkवास्तव में वैसे भी इसे संशोधित नहीं करना चाहिए।


3

ऊपर दिए गए पहले उदाहरण मार्टिंस पर थोड़ा बदलाव, अगर लूप के अंदर से बचा जाता है:

Status = None
for c in [check_size, check_color, check_tone, check_flavor]:
  Status = Status or c();
return Status

क्या यह? आप अभी भी एक तुलना करते हैं। अपने संस्करण में आप सभी स्थितियों की परवाह किए बिना जांच करेंगे और एक सत्य मूल्य के पहले उदाहरण पर वापस नहीं आएंगे, उन कार्यों को कितना महंगा है, इस पर निर्भर रहना, जो वांछनीय नहीं हो सकता है।
रिटि।

4
@ Reti43: Status or c()छोड़ देगा / शॉर्ट सर्किट के लिए कॉल का मूल्यांकन c()करता है, तो Statustruthy है, इसलिए इस जवाब में कोड ओपी के कोड से किसी भी अधिक कार्यों कॉल करने के लिए प्रकट नहीं होता। stackoverflow.com/questions/2580136/…
नील स्लेटर

2
@NeilSlater सच। केवल नकारात्मक पक्ष यह है कि सबसे अच्छा मामला अब ओ (एन) में है क्योंकि सूचीकर्ता को एन बार उपज देना पड़ता है, जब यह ओ (1) से पहले होता है यदि पहला फ़ंक्शन ओ (1) में कुछ सच्चाई देता है।
टाइमजैब

1
हाँ अच्छे अंक। मुझे बस यह आशा करनी है कि लगभग खाली लूप को लूप करने की तुलना में सी () को थोड़ा अधिक समय लगता है। यदि यह एक अच्छा है तो स्वाद की जाँच में पूरी शाम लग सकती है।
मैथ्रेडलर

3

मुझे @ टाइमगैब पसंद है। इस बीच मैं यह जोड़ना चाहूंगा कि बयान Noneमें व्यक्त returnकरने की आवश्यकता नहीं है क्योंकि orअलग किए गए बयानों के संग्रह का मूल्यांकन किया जाता है और पहले कोई भी शून्य, शून्य-खाली, कोई नहीं-कोई नहीं लौटा है और यदि कोई नहीं है तो Noneवापस लौटा दिया जाता है है Noneया नहीं!

तो मेरा check_all_conditions()काम इस तरह दिखता है:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor()

उपयोग के timeitसाथ number=10**7मैंने कई सुझावों के चल रहे समय को देखा। तुलना के लिए मैंने सिर्फ random.random()एक स्ट्रिंग वापस करने के लिए फ़ंक्शन का उपयोग किया या Noneयादृच्छिक संख्याओं के आधार पर। यहाँ पूरा कोड है:

import random
import timeit

def check_size():
    if random.random() < 0.25: return "BIG"

def check_color():
    if random.random() < 0.25: return "RED"

def check_tone():
    if random.random() < 0.25: return "SOFT"

def check_flavor():
    if random.random() < 0.25: return "SWEET"

def check_all_conditions_Bernard():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

def check_all_Martijn_Pieters():
    conditions = (check_size, check_color, check_tone, check_flavor)
    for condition in conditions:
        result = condition()
        if result:
            return result

def check_all_conditions_timgeb():
    return check_size() or check_color() or check_tone() or check_flavor() or None

def check_all_conditions_Reza():
    return check_size() or check_color() or check_tone() or check_flavor()

def check_all_conditions_Phinet():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions_Phil_Frost():
    for condition in all_conditions():
        if condition:
            return condition

def main():
    num = 10000000
    random.seed(20)
    print("Bernard:", timeit.timeit('check_all_conditions_Bernard()', 'from __main__ import check_all_conditions_Bernard', number=num))
    random.seed(20)
    print("Martijn Pieters:", timeit.timeit('check_all_Martijn_Pieters()', 'from __main__ import check_all_Martijn_Pieters', number=num))
    random.seed(20)
    print("timgeb:", timeit.timeit('check_all_conditions_timgeb()', 'from __main__ import check_all_conditions_timgeb', number=num))
    random.seed(20)
    print("Reza:", timeit.timeit('check_all_conditions_Reza()', 'from __main__ import check_all_conditions_Reza', number=num))
    random.seed(20)
    print("Phinet:", timeit.timeit('check_all_conditions_Phinet()', 'from __main__ import check_all_conditions_Phinet', number=num))
    random.seed(20)
    print("Phil Frost:", timeit.timeit('check_all_conditions_Phil_Frost()', 'from __main__ import check_all_conditions_Phil_Frost', number=num))

if __name__ == '__main__':
    main()

और यहाँ परिणाम हैं:

Bernard: 7.398444877040768
Martijn Pieters: 8.506569201346597
timgeb: 7.244275416364456
Reza: 6.982133448743038
Phinet: 7.925932800076634
Phil Frost: 11.924794811353031

2

यह तरीका बॉक्स के बाहर थोड़ा सा है, लेकिन मुझे लगता है कि अंतिम परिणाम सरल, पठनीय और अच्छा लग रहा है।

मूल विचार raiseएक अपवाद है जब कोई एक कार्य सत्य के रूप में मूल्यांकन करता है, और परिणाम लौटाता है। यहाँ है कि यह कैसे दिख सकता है:

def check_conditions():
    try:
        assertFalsey(
            check_size,
            check_color,
            check_tone,
            check_flavor)
    except TruthyException as e:
        return e.trigger
    else:
        return None

आपको एक assertFalseyफ़ंक्शन की आवश्यकता होगी जो अपवाद को उठाता है जब एक फ़ंक्शन फ़ंक्शन तर्क सत्य के रूप में मूल्यांकन करता है:

def assertFalsey(*funcs):
    for f in funcs:
        o = f()
        if o:
            raise TruthyException(o)

उपरोक्त को संशोधित किया जा सकता है ताकि कार्यों के मूल्यांकन के लिए भी तर्क प्रदान किया जा सके।

और निश्चित ही आपको इसकी आवश्यकता होगी TruthyException। यह अपवाद अपवाद objectको ट्रिगर करता है:

class TruthyException(Exception):
    def __init__(self, obj, *args):
        super().__init__(*args)
        self.trigger = obj

आप मूल फ़ंक्शन को कुछ और सामान्य चीज़ों में बदल सकते हैं:

def get_truthy_condition(*conditions):
    try:
        assertFalsey(*conditions)
    except TruthyException as e:
        return e.trigger
    else:
        return None

result = get_truthy_condition(check_size, check_color, check_tone, check_flavor)

यह थोड़ा धीमा हो सकता है क्योंकि आप एक ifबयान का उपयोग कर रहे हैं और एक अपवाद को संभाल रहे हैं। हालाँकि, अपवाद को केवल एक बार अधिकतम नियंत्रित किया जाता है, इसलिए प्रदर्शन के लिए हिट तब तक मामूली होना चाहिए जब तक आप चेक को चलाने की उम्मीद नहीं करते हैं और Trueकई हजारों बार मूल्य प्राप्त करते हैं ।


// , प्यारा! क्या इस तरह की चीज़ के लिए अपवाद हैंडलिंग का उपयोग करना "पायथन" माना जाता है?
नाथन बसानी

@NathanBasanese ज़रूर- अपवादों का इस्तेमाल हर समय नियंत्रण प्रवाह के लिए किया जाता है। StopIterationएक बहुत अच्छा उदाहरण है: एक अपवाद हर बार उठाया जाता है जब आप एक चलने योग्य निकास करते हैं। आप जिस चीज से बचना चाहते हैं, वह क्रमिक रूप से बार-बार अपवादों को बढ़ा रही है, जो महंगी हो जाएगी। लेकिन ऐसा एक बार करना नहीं है।
रिक

//, आह, मुझे लगता है कि आप प्रोग्रामर.स्टैकएक्सचेंज . com/questions/112463/… जैसी किसी चीज़ का जिक्र कर रहे हैं । मैंने उस प्रश्न के लिए और इस उत्तर के लिए मतदान किया है। इसके लिए पायथन 3 डॉक्स यहां हैं: docs.python.org/3/library/stdtypes.html#iterator-types , मुझे लगता है।
नाथन बसानी

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

@ बैकलाइटिंग मैं सहमत हूं। मैं वास्तव में खुद ऐसा कभी नहीं करूँगा। ओपी ने दोहराया कोड से बचने के तरीके पूछे, लेकिन मुझे लगता है कि उसने जो शुरू किया वह पूरी तरह से ठीक है।
रिक

2

पाइथोनिक तरीका या तो कम करने का उपयोग कर रहा है (जैसा कि किसी ने पहले ही उल्लेख किया है) या इटर्टूलस (जैसा कि नीचे दिखाया गया है), लेकिन यह मुझे लगता है कि बस orऑपरेटर की शॉर्ट सर्किटिंग का उपयोग करके स्पष्ट कोड का उत्पादन होता है

from itertools import imap, dropwhile

def check_all_conditions():
    conditions = (check_size,\
        check_color,\
        check_tone,\
        check_flavor)
    results_gen = dropwhile(lambda x:not x, imap(lambda check:check(), conditions))
    try:
        return results_gen.next()
    except StopIteration:
        return None

0

मैं यहाँ कूदने जा रहा हूँ और पायथन की एक भी पंक्ति कभी नहीं लिखी है, लेकिन मुझे लगता if x = check_something(): return xहै कि यह मान्य है?

यदि ऐसा है तो:

def check_all_conditions():

    if (x := check_size()): return x
    if (x := check_color()): return x
    if (x := check_tone()): return x
    if (x := check_flavor()): return x

    return None

1
यह मान्य नहीं है पायथन, नहीं। अजगर आपको असाइनमेंट ऑपरेटर की तरह इस्तेमाल नहीं करने देता। हालाँकि, एक नई विशेष असाइनमेंट अभिव्यक्ति को हाल ही में जोड़ा गया था, इसलिए अब आप if ( x := check_size() ) :उसी प्रभाव के लिए लिख सकते हैं ।
जैक एडली


-2

मैंने अतीत में dicts के साथ स्विच / केस स्टेटमेंट के कुछ दिलचस्प कार्यान्वयन देखे हैं जिसने मुझे इस उत्तर की ओर ले गया। आपके द्वारा दिए गए उदाहरण का उपयोग करके आपको निम्नलिखित मिलेगा। (यह पागलपन है using_complete_sentences_for_function_names, इसलिए check_all_conditionsइसका नाम बदल दिया गया है status। देखें (1))

def status(k = 'a', s = {'a':'b','b':'c','c':'d','d':None}) :
  select = lambda next, test : test if test else next
  d = {'a': lambda : select(s['a'], check_size()  ),
       'b': lambda : select(s['b'], check_color() ),
       'c': lambda : select(s['c'], check_tone()  ),
       'd': lambda : select(s['d'], check_flavor())}
  while k in d : k = d[k]()
  return k

चयनित फ़ंक्शन प्रत्येक check_FUNCTIONदो बार कॉल करने की आवश्यकता को समाप्त करता है यानी आप check_FUNCTION() if check_FUNCTION() else nextएक और फ़ंक्शन परत जोड़कर बचते हैं । यह लंबे समय तक चलने वाले कार्यों के लिए उपयोगी है। लम्‍बदास ने इसके विलंबित निष्‍पादन के निष्पादन को लूप तक मान लिया।

एक बोनस के रूप में आप निष्पादन आदेश को संशोधित कर सकते हैं और यहां तक ​​कि कुछ परीक्षणों को बदलकर छोड़ सकते हैं kऔर sउदाहरण k='c',s={'c':'b','b':None}के लिए परीक्षणों की संख्या कम कर देता है और मूल प्रसंस्करण क्रम को उलट देता है।

timeitसाथियों को देखने लेकिन आप अधिक कोड की कमनीयता के साथ संबंध प्रतीत एक अतिरिक्त परत या ढेर करने के लिए दो और dict के लिए लागत को जोड़ने की लागत पर झंझट हो सकता है।

वैकल्पिक रूप से एक सरल कार्यान्वयन निम्नलिखित हो सकता है:

def status(k=check_size) :
  select = lambda next, test : test if test else next
  d = {check_size  : lambda : select(check_color,  check_size()  ),
       check_color : lambda : select(check_tone,   check_color() ),
       check_tone  : lambda : select(check_flavor, check_tone()  ),
       check_flavor: lambda : select(None,         check_flavor())}
  while k in d : k = d[k]()
  return k
  1. मेरा मतलब यह है कि pep8 के संदर्भ में नहीं, बल्कि एक वाक्य के स्थान पर एक संक्षिप्त वर्णनात्मक शब्द का उपयोग करने के संदर्भ में। दी गई ओपी कुछ कोडिंग कन्वेंशन का अनुसरण कर रही हो सकती है, जो किसी मौजूदा कोड बेस पर काम कर रही हो या अपने कोडबेस में टेरर टर्म्स की परवाह न करती हो।

1
कभी-कभी लोग अपने नामकरण के साथ वास्तव में पागल हो जाते हैं जब एक शब्द करेगा। एक उदाहरण के रूप में ओपी के कोड का उपयोग करना यह संभावना नहीं है कि उसके पास फ़ंक्शन होंगे, check_no/some/even/prime/every_third/fancy_conditionsलेकिन यह केवल एक फ़ंक्शन है इसलिए इसे कॉल न करें statusया यदि कोई जोर देता है check_status_all_अति प्रयोग करना , वह ब्रह्मांड की अखंडता को सुनिश्चित नहीं कर रहा है। नामकरण निश्चित रूप से जब भी संभव हो, नाम रखने वाले कीवर्ड का लगातार सेट का उपयोग करना चाहिए। सबसे लंबे वाक्य सबसे अच्छे डॉकस्ट्रिंग्स के रूप में काम करते हैं। शायद ही कभी किसी चीज का वर्णन करने के लिए 8-10 अक्षरों की आवश्यकता होती है।
कैरेल

1
मैं लंबे फ़ंक्शन नामों का प्रशंसक हूं, क्योंकि मैं चाहता हूं कि उच्च-स्तरीय फ़ंक्शन स्व-दस्तावेजीकरण हो। लेकिन check_all_conditionsएक बुरा नाम है, क्योंकि यह सभी स्थितियों की जाँच नहीं कर रहा है अगर एक सच है। मैं कुछ का उपयोग करता हूँ matches_any_condition
जॉन हजेन

यह एक दिलचस्प चाल है। मैं अक्षरों की संख्या को कम से कम करने की कोशिश करता हूं, जो मैं बाद में टाइपो बनाऊंगा :) ऐसा लगता है कि मैंने अपने समाधान में राय का ढेर लगा दिया है, जब मैं वास्तव में एक सहायक संकेत प्रदान करने की कोशिश कर रहा था। क्या इसे संपादित किया जाना चाहिए?
केयरएल

2
ऐसा लगता है कि बहुत अधिक हैक किया गया है, विशेष रूप से इस प्रश्न पर अन्य समाधानों पर विचार कर रहा है। ओपी जो करने की कोशिश कर रहा है वह बिल्कुल जटिल नहीं है; समाधान इतना सरल होना चाहिए कि वह आधा सो सके। और मुझे नहीं पता कि यहां क्या हो रहा है।
ब्लैकलाइट शाइनिंग

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