सफलता या असफलता होने पर बुलियन लौटाना एकमात्र चिंता का विषय है


15

मैं अक्सर खुद को एक विधि से बूलियन को वापस पाता हूं, जिसका उपयोग कई स्थानों पर किया जाता है, ताकि एक ही स्थान पर उस पद्धति के सभी तर्क समाहित किए जा सकें। सभी (आंतरिक) कॉलिंग विधि को यह जानना आवश्यक है कि ऑपरेशन सफल हुआ था, या नहीं।

मैं पायथन का उपयोग कर रहा हूं, लेकिन यह प्रश्न उस भाषा के लिए आवश्यक नहीं है। मेरे विचार से केवल दो विकल्प हैं

  1. एक अपवाद उठाएं, हालांकि परिस्थितियां असाधारण नहीं हैं, और उस अपवाद को पकड़ने के लिए याद रखें जहां हर जगह फ़ंक्शन को बुलाया जाता है
  2. मैं कर रहा हूँ के रूप में एक बूलियन लौटें।

यह एक बहुत ही सरल उदाहरण है जो दर्शाता है कि मैं किस बारे में बात कर रहा हूं।

import os

class DoSomething(object):

    def remove_file(self, filename):

        try:
            os.remove(filename)
        except OSError:
            return False

        return True

    def process_file(self, filename):

        do_something()

        if remove_file(filename):
            do_something_else()

यद्यपि यह कार्यात्मक है, मैं वास्तव में कुछ करने के इस तरीके को नापसंद करता हूं, यह "बदबू आ रही है", और कभी-कभी बहुत सारे नेस्टेड इफ़ेक्ट हो सकते हैं। लेकिन, मैं एक सरल तरीके के बारे में नहीं सोच सकता।

मैं एक और LBYL दर्शन और उपयोग की ओर मुड़ सकता हूं os.path.exists(filename) विलोपन का प्रयास करने से पहले लेकिन इस बात की कोई गारंटी नहीं है कि फ़ाइल को इस बीच लॉक नहीं किया गया होगा (यह संभव नहीं है लेकिन संभव है) और मुझे अभी भी यह निर्धारित करना है कि विलोपन सफल रहा है या नहीं।

क्या यह एक "स्वीकार्य" डिज़ाइन है और यदि नहीं तो यह डिज़ाइन करने का एक बेहतर तरीका क्या होगा?

जवाबों:


11

booleanतार्किक निर्णय लेने में विधि / कार्य उपयोगी होने पर आपको वापस लौटना चाहिए ।

exceptionजब कोई विधि / फ़ंक्शन तार्किक निर्णयों में उपयोग होने की संभावना नहीं है, तो आपको फेंक देना चाहिए ।

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

एक और अभ्यास objectsपरिणाम के बजाय वापस आना है । यदि आप कॉल करते हैं open, तो यह एक Fileवस्तु वापस करना चाहिए या nullयदि खोलने में असमर्थ है। यह सुनिश्चित करता है कि प्रोग्रामर के पास एक ऑब्जेक्ट इंस्टेंस है जो एक वैध स्थिति में है जिसका उपयोग किया जा सकता है।

संपादित करें:

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


यह एक सत्यापन है कि मैं क्या कर रहा हूं इसलिए मुझे उत्तर पसंद है :-)। वस्तुओं पर, हालांकि मैं समझता हूं कि आप कहां से आ रहे हैं मैं यह नहीं देखता कि यह उन मामलों में मदद करता है जो मैं इसका उपयोग करता हूं। मैं DRY होना चाहता हूं इसलिए मैं किसी एक तरीके से ऑब्जेक्ट को वापस लेने जा रहा हूं क्योंकि मैं केवल एक चीज करना चाहता हूं। मैं अब एक ही कोड के साथ बचा हुआ हूं, एक अतिरिक्त विधि के साथ सहेजें। (यह भी दिए गए उदाहरण के लिए कि मैं फ़ाइल को हटा रहा हूँ इसलिए एक अशक्त फ़ाइल ऑब्जेक्ट ज्यादा नहीं कहता है :-)
बेन

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

4

इस पर आपका अंतर्ज्ञान सही है, ऐसा करने का एक बेहतर तरीका है: भिक्षुओं

मोनाड क्या हैं?

मोनाड हैं (विकिपीडिया को विराम देने के लिए) जंजीर तंत्र को छुपाने के दौरान एक साथ परिचालन संचालन का एक तरीका; आपके मामले में जंजीर तंत्र नेस्टेड ifएस है। उसे छिपाएं और आपका कोड बहुत अच्छे को गंध देगा ।

भिक्षुओं के एक जोड़े हैं जो सिर्फ इतना करेंगे ("शायद" और "या तो") और आपके लिए भाग्यशाली हैं कि वे वास्तव में एक अच्छा अजगर मठ पुस्तकालय का हिस्सा हैं!

वे आपके कोड के लिए क्या कर सकते हैं

यहाँ एक उदाहरण "या तो" मोनाड ("लाइब्रेरी में फेल्ड" से जुड़ा हुआ है) का उपयोग करके किया गया है, जहाँ कोई फ़ंक्शन सफलता या विफलता को वापस ला सकता है, जो कि हुआ पर निर्भर करता है:

import os

class DoSomething(object):

    def remove_file(self, filename):
        try:
            os.remove(filename)
            return Success(None)
        except OSError:
            return Failure("There was an OS Error.")

    @do(Failable)
    def process_file(self, filename):
        do_something()
        yield remove_file(filename)
        do_something_else()
        mreturn(Success("All ok."))

अब, यह अब आपके पास मौजूद चीज़ों से बहुत भिन्न नहीं हो सकता है, लेकिन विचार करें कि यदि आपके पास अधिक संचालन होता है तो परिणाम कैसे होंगे, जिसके परिणामस्वरूप विफलता हो सकती है:

    def action_that_might_fail_and_returns_something(self):
        # get some random value between 0 and 1 here
        if value < 0.5:
            return Success(value)
        else:
            return Failure("Bad value! Bad! Go to your room!")

    @do(Failable)
    def process_file(self, filename):
        do_something()
        yield remove_file(filename)
        yield action_that_might_fail(somearg)
        yield another_action_that_might_fail(someotherarg)
        some_val = yield action_that_might_fail_and_returns_something()
        yield something_that_used_the_return_value(some_val)
        do_something_else()
        mreturn(Success("All ok."))

फ़ंक्शन yieldमें प्रत्येक में process_file, यदि फ़ंक्शन कॉल में विफलता होती है, तो process_fileफ़ंक्शन बाहर निकल जाएगा, उस बिंदु पर , विफल फ़ंक्शन से विफलता मूल्य वापस करने के बजाय, बाकी के माध्यम से जारी रखने और वापस लौटने के बजाय।Success("All ok.")

अब, नेस्टेड ifएस के साथ उपरोक्त करने की कल्पना करो ! (आप रिटर्न वैल्यू को कैसे संभालेंगे !?)

निष्कर्ष

भिक्षु अच्छे हैं :)


टिप्पणियाँ:

मैं पायथन प्रोग्रामर नहीं हूं - मैंने कुछ प्रोजेक्ट ऑटोमेशन के लिए एक स्क्रिप्ट I Ninja'd में ऊपर से जुड़े मोनाड लाइब्रेरी का इस्तेमाल किया। मैं इकट्ठा करता हूं, हालांकि, सामान्य तौर पर, पसंदीदा, मुहावरेदार दृष्टिकोण अपवादों का उपयोग करना है।

IIRC वहाँ लिपि में लिपि लिपि में एक टाइपो है, हालांकि मैं भूल जाता हूं कि यह एटीएम कहां है। मुझे याद है तो मैं अपडेट करूंगा। मैंने पृष्ठ के विरुद्ध अपने संस्करण को अलग कर दिया और पाया: def failable_monad_examle():-> def failable_monad_example():- pइन द exampleअनुपलब्ध था।

फेलियर डेकोरेटेड फंक्शन (जैसे process_file) का रिजल्ट पाने के लिए आपको रिजल्ट कैप्चर variableकरना होगा और variable.valueइसे पाने के लिए ए ।


2

एक फ़ंक्शन एक अनुबंध है, और इसके नाम को सुझाव देना चाहिए कि यह किस अनुबंध को पूरा करेगा। IMHO, यदि आप इसे नाम देते हैं remove_fileतो यह फ़ाइल को हटा देना चाहिए और ऐसा करने में विफल होने पर अपवाद का कारण बनना चाहिए। दूसरी ओर, यदि आप इसे नाम देते हैं try_remove_file, तो यह निकालने की बूलियन को हटाने और वापस करने के लिए "प्रयास" करना चाहिए कि क्या फ़ाइल को हटा दिया गया है या नहीं।

इससे एक और सवाल पैदा होगा - यह होना चाहिए remove_fileया try_remove_file? यह आपकी कॉल साइट पर निर्भर करता है। वास्तव में, आपके पास दोनों विधियाँ हो सकती हैं और विभिन्न परिदृश्यों में उनका उपयोग किया जा सकता है, लेकिन मुझे लगता है कि फ़ाइल को हटाने से सफलता की उच्च संभावना है इसलिए मैं remove_fileअसफल होने पर केवल उस अपवाद को रखना पसंद करता हूं ।


0

इस विशेष मामले में यह सोचना उपयोगी हो सकता है कि आप फ़ाइल को हटाने में सक्षम क्यों नहीं हो सकते हैं। मान लीजिए कि समस्या यह है कि फ़ाइल मौजूद हो सकती है या नहीं। फिर आपके पास एक फ़ंक्शन होना चाहिए जो doesFileExist()सही या गलत लौटाता है, और एक फ़ंक्शन removeFile()जो बस फ़ाइल को हटा देता है।

आपके कोड में अगर फ़ाइल मौजूद है, तो आप पहले जाँच करेंगे। अगर ऐसा होता है, तो कॉल करें removeFile। यदि नहीं, तो अन्य सामान करें।

इस मामले में आप अभी भी removeFileएक अपवाद फेंकना चाह सकते हैं यदि फ़ाइल को किसी अन्य कारण से हटाया नहीं जा सकता है, जैसे कि अनुमतियाँ।

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


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

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