अजगर: क्या यह __in__ के भीतर अपवादों को बढ़ाने के लिए बुरा है?


128

क्या अपवादों को उठाने के लिए इसे बुरा माना जाता है __init__? यदि ऐसा है, तो एक निश्चित श्रेणी चर के रूप में Noneया एक गलत प्रकार के रूप में आरंभ होने पर त्रुटि को फेंकने की स्वीकृत विधि क्या है ?


सी में, यह विध्वंसक में एक अपवाद को बढ़ाने के लिए बुरा रूप है, लेकिन निर्माता ठीक होना चाहिए।
कैलीथ

6
@ काइल, आपका मतलब है सी ++ - सी में कोई कंस्ट्रक्टर या विध्वंसक नहीं हैं
एलेक्स मार्टेली

4
... या अपवाद, उस बात के लिए।
मैट विल्डिंग

@ जयजयकार: योग्य, कृपया निर्दोष टाइपो द्वारा किए गए उस निरर्थक बयान को दूर करें ;-)
lpapp

4
@lpapp हाँ। सी ++। एफएमएल। और मैं उस टिप्पणी को संपादित नहीं कर सका। तो इंटरनेट मेरी
मूढ़ता का

जवाबों:


159

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

त्रुटि वर्ग, निश्चित रूप से, आपके ऊपर है। ValueErrorसबसे अच्छा है अगर कंस्ट्रक्टर को एक अमान्य पैरामीटर पारित किया गया था।


14
कंस्ट्रक्टर में सबसे अधिक उपयोग किए जाने वाले अपवाद हैं ValueErrorऔर TypeError
डेनिस ओटकिडैच

9
बस इशारा कर रहा है कि __init__कंस्ट्रक्टर नहीं है, इसके इंतिहाईज़र हैं। आप लाइन को संपादित करना चाह सकते हैं । एक कंस्ट्रक्टर के भीतर त्रुटि की स्थिति को इंगित करने का कोई और अच्छा तरीका नहीं है,
हारिस

26

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

class NetworkInterface:
    def __init__(self, address)
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect(address)
        self.stream = self.socket.makefile()

    def __del__(self)
        self.stream.close()
        self.socket.close()

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


यह उत्तर वास्तव में उपयोगी है। यह केवल "हरी बत्ती" के बारे में नहीं बोल रहा है, लेकिन "विध्वंसक" के साथ एक उदाहरण का उल्लेख करता है।
lpapp

आपका पायथन कोड इसमें विफल रहता है __del__क्योंकि यह बुरी तरह से लिखा गया है। यदि आप this->p_socket->close()C ++ में एक विध्वंसक में करते हैं तो आपको बिल्कुल वही समस्या होगी । C ++ में, आप ऐसा नहीं करेंगे - आप सदस्य ऑब्जेक्ट को स्वयं नष्ट कर देंगे। अजगर में भी ऐसा ही करें।
एरिक

1
@ मुझे C ++ में समस्या नहीं होगी क्योंकि C ++ उन ऑब्जेक्ट्स को नष्ट नहीं करता है जिन्हें ठीक से इनिशियलाइज़ नहीं किया गया है । वास्तव में यह C ++ में एक बहुत ही सामान्य मुहावरा है जो कंस्ट्रक्टर में संसाधनों को आवंटित करने और उन्हें विध्वंसक में निपटाने के लिए है । आप सुझाव देते हैं कि सदस्य वस्तु स्वयं नष्ट हो जाती है (इसके विध्वंसक में संसाधनों को नष्ट करना) - तब सदस्य वर्ग को लिखते समय भी यही समस्या उत्पन्न होती है।
सेप्पो एनारवी

11

मुझे ऐसा कोई कारण नहीं दिख रहा है कि यह खराब हो।

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


6

मानक पुस्तकालय कहते हैं:

>>> f = file("notexisting.txt")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'notexisting.txt'

इसके अलावा, मुझे वास्तव में कोई कारण नहीं दिखाई देता है कि इसे क्यों खराब माना जाए।


3

मुझे यह सोचना चाहिए कि यह बिल्ट-इन ValueErrorअपवाद के लिए एकदम सही मामला है।


2

मैं उपरोक्त सभी के साथ सहमत हूं।

वास्तव में यह संकेत देने का कोई अन्य तरीका नहीं है कि एक अपवाद को बढ़ाने के अलावा किसी वस्तु के प्रारंभिककरण में कुछ गलत हुआ।

अधिकांश कार्यक्रमों की कक्षाओं में जहां एक वर्ग की स्थिति पूरी तरह से उस वर्ग के इनपुट पर निर्भर होती है, हम उम्मीद कर सकते हैं कि किसी प्रकार के ValueError या TypeError को उठाया जा सकता है।

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


2

Init से त्रुटियों को उठाना कुछ मामलों में अपरिहार्य है, लेकिन init में बहुत अधिक कार्य करना एक गलत शैली है। आपको एक कारखाना या एक छद्म कारखाना बनाने पर विचार करना चाहिए - एक साधारण वर्गमिथोड जो कि वस्तु को वापस करता है।

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