पायथन: मैं कैसे जान सकता हूं कि कौन से अपवाद एक विधि कॉल से फेंके जा सकते हैं


89

क्या एक तरीका है (कोडिंग के समय) जानने के लिए जो अजगर कोड को निष्पादित करते समय उम्मीद करता है? मैं अंत में बेस एक्सेप्शन क्लास 90% पकड़ रहा हूं क्योंकि मुझे नहीं पता है कि कौन सा अपवाद प्रकार फेंका जा सकता है (और मुझे दस्तावेज़ पढ़ने के लिए मत कहो। कई बार गहरे से एक अपवाद का प्रचार किया जा सकता है। समय प्रलेखन अद्यतन या सही नहीं है)। क्या यह जाँचने के लिए किसी प्रकार का उपकरण है? (जैसे अजगर कोड और libs पढ़कर)?


2
इस बात को ध्यान में रखें कि पायथन <2.6 में, आप raiseसबक्लासेस ही नहीं, बल्कि तार भी लगा सकते हैं BaseException। इसलिए यदि आप लाइब्रेरी कोड में कॉल कर रहे हैं जो आपके नियंत्रण से बाहर है, तो भी except Exceptionपर्याप्त नहीं है, क्योंकि यह स्ट्रिंग अपवादों को नहीं पकड़ेगा। जैसा कि दूसरों ने बताया है, आप यहाँ गलत पेड़ को भौंक रहे हैं।
डैनियल प्राइडेन

मुझे नहीं पता था। मुझे लगा अपवाद के अलावा: .. लगभग सब कुछ पकड़ता है।
गैबीमे

2
except Exceptionपायथन 2.6 और बाद में स्ट्रिंग अपवादों को पकड़ने के लिए ठीक काम करता है।
जेफरी हैरिस

जवाबों:


22

मुझे लगता है कि स्थैतिक टाइपिंग नियमों की कमी के कारण एक समाधान केवल असंभव हो सकता है।

मुझे अपवादों की जाँच करने वाले कुछ उपकरण के बारे में पता नहीं है, लेकिन आप अपनी ज़रूरतों के अनुरूप अपने उपकरण के साथ आ सकते हैं (स्थैतिक विश्लेषण के साथ थोड़ा खेलने का अच्छा मौका)।

पहले प्रयास के रूप में, आप एक फ़ंक्शन लिख सकते हैं जो एक एएसटी का निर्माण करता है, सभी Raiseनोड्स को ढूंढता है , और फिर अपवादों को बढ़ाने के सामान्य पैटर्न का पता लगाने की कोशिश करता है (जैसे सीधे एक निर्माता को कॉल करना)

xनिम्नलिखित कार्यक्रम होने दें :

x = '''\
if f(x):
    raise IOError(errno.ENOENT, 'not found')
else:
    e = g(x)
    raise e
'''

compilerपैकेज का उपयोग करके एएसटी का निर्माण करें :

tree = compiler.parse(x)

फिर एक Raiseआगंतुक वर्ग को परिभाषित करें :

class RaiseVisitor(object):
    def __init__(self):
        self.nodes = []
    def visitRaise(self, n):
        self.nodes.append(n)

और एएसटी एकत्रित Raiseनोड्स चलना :

v = RaiseVisitor()
compiler.walk(tree, v)

>>> print v.nodes
[
    Raise(
        CallFunc(
            Name('IOError'),
            [Getattr(Name('errno'), 'ENOENT'), Const('not found')],
            None, None),
        None, None),
    Raise(Name('e'), None, None),
]

आप संकलक प्रतीक तालिकाओं का उपयोग करके, डेटा निर्भरता आदि का विश्लेषण करके प्रतीकों को हल करके जारी रख सकते हैं या आप बस घटा सकते हैं, कि CallFunc(Name('IOError'), ...)"निश्चित रूप से मतलब उठाना चाहिए IOError", जो त्वरित व्यावहारिक परिणामों के लिए काफी ठीक है :)


इस दिलचस्प जवाब के लिए धन्यवाद। हालांकि यह नहीं समझा गया कि मुझे सभी उठाए गए नोड्स के अलावा कुछ और क्यों देखना चाहिए। मुझे "संकलक डेटा तालिकाओं का विश्लेषण करते हुए संकलक प्रतीक तालिकाओं का उपयोग करके प्रतीकों का समाधान क्यों करना चाहिए"? क्या अपवाद को बढ़ाने का एकमात्र तरीका यह नहीं है कि बढ़ाएँ ()?
गेबीमे

1
v.nodesऊपर दिए गए मूल्य को देखते हुए , आप वास्तव में यह नहीं कह सकते हैं कि क्या चीज है Name('IOError')या Name('e')। आप नहीं जानते कि वे कौन से मूल्य हैं IOErrorऔर eइंगित कर सकते हैं, क्योंकि वे तथाकथित मुक्त चर हैं। यहां तक ​​कि अगर उनके बाध्यकारी संदर्भ को ज्ञात किया गया था (यहां प्रतीक तालिकाओं को खेलने में आता है), तो आपको उनके सटीक मानों का पता लगाने के लिए कुछ प्रकार की डेटा निर्भरता विश्लेषण करना चाहिए (यह पायथन में कठिन होना चाहिए)।
एंड्री वाल्स्सोविच शेख

जैसा कि आप एक व्यावहारिक अर्ध-स्वचालित समाधान की तलाश में हैं, ['IOError(errno.ENOENT, "not found")', 'e']उपयोगकर्ता को प्रदर्शित की गई सूची ठीक है। लेकिन आप स्ट्रिंग्स द्वारा दर्शाए गए चर के मूल्यों की वास्तविक कक्षाओं का अनुमान नहीं लगा सकते हैं :) (
पश्चाताप के

1
हाँ। यह तरीका, हालांकि चतुर, वास्तव में आपको एक पूर्ण कवरेज नहीं देता है। पायथन की गतिशील प्रकृति के कारण, यह पूरी तरह से संभव है (हालांकि स्पष्ट रूप से एक बुरा विचार) कोड के लिए आप ऐसा करने के लिए कह रहे हैं exc_class = raw_input(); exec "raise " + exc_class। मुद्दा यह है कि पायथन जैसी गतिशील भाषा में इस तरह का स्थैतिक विश्लेषण वास्तव में संभव नहीं है।
डैनियल प्राइडेन

7
वैसे, आप बस find /path/to/library -name '*.py' | grep 'raise 'इसी तरह के परिणाम प्राप्त करने के लिए कर सकते हैं :)
एंड्री Vlasovskikh

23

आपको केवल अपवादों को पकड़ना चाहिए जिन्हें आप संभाल लेंगे।

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

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

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

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

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


27
ज़रूर, लेकिन कोई यह कैसे तय कर सकता है कि अगर उसे पता नहीं है कि उसे क्या संभालना चाहिए?
गैबीमे

@ Bugspy.net, ने इस मामले को दर्शाने के लिए मेरा जवाब तय किया
P Shved

शायद यह स्रोत कोड विश्लेषक का समय है जो यह पता लगा सकता है? मुझे लगता है कि विकसित करने के लिए बहुत मुश्किल नहीं होना चाहिए
GabiMe

@ Bugspy.net, मैंने क्लॉज़ को स्वीकार कर लिया है कि शायद इसके लिए समय क्यों न हो।
पी मुंडा

निश्चित ही आप सही हैं। हालांकि यह अभी भी दिलचस्प हो सकता है - विकास के दौरान - यह जानने के लिए कि किस प्रकार के अपवाद हो सकते हैं।
hek2mgl

11

इस समस्या को हल करने के लिए सही उपकरण unittests है। यदि आपके पास वास्तविक कोड द्वारा उठाए गए अपवाद हैं जो कि unittests नहीं बढ़ाते हैं, तो आपको अधिक unittests की आवश्यकता है।

इस पर विचार करो

def f(duck):
    try:
        duck.quack()
    except ??? could be anything

बत्तख कोई भी वस्तु हो सकती है

जाहिर है कि आपके पास एक AttributeErrorबतख हो सकती है , TypeErrorलेकिन एक बतख के पास एक नीम नहीं है, लेकिन यह कॉल करने योग्य नहीं है। आपको कोई अंदाजा नहीं है कि क्या duck.quack()हो सकता है, हालांकि, एक DuckErrorया कुछ भी उठा सकते हैं

अब मान लीजिए कि आपके पास इस तरह का कोड है

arr[i] = get_something_from_database()

यदि यह उठाता है IndexErrorतो आप यह नहीं जानते कि यह गिरफ्तारी [i] से आया है या डेटाबेस फ़ंक्शन के अंदर से। आमतौर पर यह बहुत मायने नहीं रखता है कि अपवाद कहां हुआ, बल्कि यह कि कुछ गलत हुआ और आप जो होना चाहते थे वह नहीं हुआ।

एक आसान तकनीक को पकड़ना है और शायद इस तरह अपवाद को रोकना है

except Exception as e
    #inspect e, decide what to do
    raise

यदि आप इसे "ररीज़" करने जा रहे हैं तो इसे बिल्कुल क्यों पकड़ें?
तरणाय कालमान

आपको इसे संक्षिप्त करने की आवश्यकता नहीं है , यही वह टिप्पणी है जिसे इंगित करना चाहिए था।
जॉन ला रूय

2
आप अपवाद को कहीं और लॉग करने के लिए चुन सकते हैं और फिर riseise
John La Rooy

3
मुझे नहीं लगता कि इकाई परीक्षण लिखना उत्तर है। सवाल यह है कि "मैं यह कैसे पता लगा सकता हूं कि किन अपवादों की अपेक्षा है" और यूनिट परीक्षण लिखने से आपको यह पता लगाने में मदद नहीं मिलेगी। वास्तव में, यूनिट टेस्ट लिखने के लिए आपको पहले से ही यह जानना होगा कि एक सही यूनिट टेस्ट लिखने के लिए आपको कौन से अपवादों की उम्मीद है ताकि आपको मूल प्रश्न के साथ-साथ प्रश्न भी पूछे जा सकें।
ब्रूनो रैनशर्ट

6

किसी ने अब तक समझाया, कि आपके पास अपवादों की पूरी, 100% सही सूची क्यों नहीं हो सकती है, इसलिए मुझे लगा कि यह टिप्पणी करने लायक है। कारणों में से एक प्रथम श्रेणी का कार्य है। मान लीजिए कि आपके पास एक फ़ंक्शन है:

def apl(f,arg):
   return f(arg)

अब aplकोई भी अपवाद उठा सकता है f। जबकि मुख्य पुस्तकालय में ऐसे कई कार्य नहीं हैं, जो कस्टम फ़िल्टर, मानचित्र, घटाना, आदि के साथ सूची समझ का उपयोग करने वाली कोई भी चीज़ प्रभावित होती है।

दस्तावेज़ीकरण और स्रोत विश्लेषक यहां जानकारी के केवल "गंभीर" स्रोत हैं। बस ध्यान रखें कि वे क्या नहीं कर सकते हैं।


5

सॉकेट का उपयोग करते समय मैं इसमें भाग गया, मैं उन सभी त्रुटि स्थितियों का पता लगाना चाहता था जो मैं अंदर चला जाऊंगा (इसलिए त्रुटियों को बनाने की कोशिश कर रहा हूं और यह पता लगाने की बजाय कि मैं क्या एक संक्षिप्त सूची चाहता हूं)। अंततः मैंने "बढ़ाएँ" के लिए grep'ing "/usr/lib64/python2.4/test/test_socket.py" समाप्त किया।

$ grep raise test_socket.py
Any exceptions raised by the clients during their tests
        raise TypeError, "test_func must be a callable function"
    raise NotImplementedError, "clientSetUp must be implemented."
    def raise_error(*args, **kwargs):
        raise socket.error
    def raise_herror(*args, **kwargs):
        raise socket.herror
    def raise_gaierror(*args, **kwargs):
        raise socket.gaierror
    self.failUnlessRaises(socket.error, raise_error,
    self.failUnlessRaises(socket.error, raise_herror,
    self.failUnlessRaises(socket.error, raise_gaierror,
        raise socket.error
    # Check that setting it to an invalid value raises ValueError
    # Check that setting it to an invalid type raises TypeError
    def raise_timeout(*args, **kwargs):
    self.failUnlessRaises(socket.timeout, raise_timeout,
    def raise_timeout(*args, **kwargs):
    self.failUnlessRaises(socket.timeout, raise_timeout,

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


4
यह मेरे तर्क को मजबूत करता है, कि पायथन में अपवाद हैंडलिंग बहुत समस्याग्रस्त है, अगर हमें कुछ बुनियादी (जो जावा में उदाहरण के लिए एक दिन से मौजूद है) से निपटने के लिए grep या स्रोत analyzers का उपयोग करने की आवश्यकता है। कभी-कभी वर्बोसिटी एक अच्छी बात है। जावा क्रिया है लेकिन कम से कम कोई आश्चर्यचकित नहीं हैं)
गैबीमे

@ गैबीमी, यह इस तरह की क्षमता नहीं है (या सामान्य रूप से स्थिर टाइपिंग) सभी बग को रोकने के लिए एक चांदी की गोली है। जावा बहुत आश्चर्य से भरा है। इसलिए ग्रहण नियमित रूप से दुर्घटनाग्रस्त होता है।
जॉन ला रूय

2

दो तरीके हैं जो मुझे जानकारीपूर्ण लगे। पहले वाला, iPython में कोड चलाते हैं, जो अपवाद प्रकार को प्रदर्शित करेगा।

n = 2
str = 'me '
str + 2
TypeError: unsupported operand type(s) for +: 'int' and 'str'

दूसरे तरीके से हम बहुत अधिक पकड़ने के लिए समझौता करते हैं और समय के साथ उस पर सुधार करते हैं। tryअपने कोड में एक अभिव्यक्ति शामिल करें और पकड़ें except Exception as err। यह जानने के लिए पर्याप्त डेटा प्रिंट करें कि क्या अपवाद फेंका गया था। अपवादों को अधिक सटीक exceptखंड जोड़कर आपके कोड में सुधार किया जाता है । जब आपको लगता है कि आपने सभी प्रासंगिक अपवादों को पकड़ लिया है, तो सभी समावेशी को हटा दें। वैसे भी एक अच्छी बात यह है कि यह प्रोग्रामिंग त्रुटियों को निगलता है।

try:
   so something
except Exception as err:
   print "Some message"
   print err.__class__
   print err
   exit(1)

1

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

डॉक्स में अंतर्निहित अपवादों की एक विस्तृत सूची है । उन अपवादों को छोड़कर कोशिश न करें जिनकी आप उम्मीद नहीं कर रहे हैं, उन्हें कॉलिंग कोड में संभाला जा सकता है।

संपादित करें : क्या फेंका जा सकता है यह स्पष्ट रूप से इस बात पर निर्भर करता है कि आप क्या कर रहे हैं! एक अनुक्रम के यादृच्छिक तत्व तक पहुँचना:, IndexErrorएक तानाशाही का यादृच्छिक तत्व: KeyErrorआदि।

बस IDLE में उन कुछ पंक्तियों को चलाने का प्रयास करें और अपवाद का कारण बनें। लेकिन unittest स्वाभाविक रूप से एक बेहतर समाधान होगा।


1
यह मेरे सरल सवाल का जवाब नहीं है। मैं यह नहीं पूछता कि मेरे अपवाद से निपटने के लिए, या कब या कैसे पकड़ना है। मैं पूछता हूं कि कैसे पता लगाया जाए कि क्या फेंका जा सकता है
गैबीमे

1
@ Bugspy.net: आप जो पूछते हैं, वह करना असंभव है और यह पूरी तरह से मान्य वर्कअराउंड है।
डैनियल प्राइडेन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.