मैं एक खौफनाक चेतावनी को कैसे पकड़ सकता हूँ जैसे कि यह एक अपवाद है (केवल परीक्षण के लिए नहीं)?


173

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

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

import numpy as np
import matplotlib.pyplot as plt
import warnings

class Lagrange:
    def __init__(self, xPts, yPts):
        self.xPts = np.array(xPts)
        self.yPts = np.array(yPts)
        self.degree = len(xPts)-1 
        self.weights = np.array([np.product([x_j - x_i for x_j in xPts if x_j != x_i]) for x_i in xPts])

    def __call__(self, x):
        warnings.filterwarnings("error")
        try:
            bigNumerator = np.product(x - self.xPts)
            numerators = np.array([bigNumerator/(x - x_j) for x_j in self.xPts])
            return sum(numerators/self.weights*self.yPts) 
        except Exception, e: # Catch division by 0. Only possible in 'numerators' array
            return yPts[np.where(xPts == x)[0][0]]

L = Lagrange([-1,0,1],[1,0,1]) # Creates quadratic poly L(x) = x^2

L(1) # This should catch an error, then return 1. 

जब इस कोड को निष्पादित किया जाता है, तो मुझे जो आउटपुट मिलता है वह है:

Warning: divide by zero encountered in int_scalars

यही चेतावनी मैं पकड़ना चाहता हूं। यह सूची समझ के अंदर होनी चाहिए।


2
क्या आपको पूरा यकीन है Warning: ...? np.array([1])/0मैं चीजों की कोशिश कर रहा हूँ जैसे कि मुझे RuntimeWarning: ...आउटपुट मिलता है ।
बकुरीउ

1
@MadPhysicist डुप्लिकेट नहीं; न्यूपी के पास पायथन के शीर्ष पर अपनी आंतरिक चेतावनी वास्तुकला है, जिसे विशेष रूप से नियंत्रित किया जा सकता है (बाकुरू द्वारा उत्तर देखें)।
gerrit

@gerrit। मैंने सही किया और एक नई बात सीखी। बैज संग्रह उन्माद को ट्रिगर करने से बचने के लिए मैंने अपनी मूल टिप्पणी को हटा दिया।
पागल भौतिक विज्ञानी

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

जवाबों:


197

ऐसा लगता है कि आपका कॉन्फ़िगरेशन इसके लिए printविकल्प का उपयोग कर रहा है numpy.seterr:

>>> import numpy as np
>>> np.array([1])/0   #'warn' mode
__main__:1: RuntimeWarning: divide by zero encountered in divide
array([0])
>>> np.seterr(all='print')
{'over': 'warn', 'divide': 'warn', 'invalid': 'warn', 'under': 'ignore'}
>>> np.array([1])/0   #'print' mode
Warning: divide by zero encountered in divide
array([0])

इसका मतलब यह है कि आप जो चेतावनी देखते हैं वह वास्तविक चेतावनी नहीं है, लेकिन यह सिर्फ कुछ वर्णों के लिए मुद्रित है stdout(दस्तावेज़ देखें seterr)। यदि आप इसे पकड़ना चाहते हैं:

  1. उपयोग करें numpy.seterr(all='raise')जो सीधे अपवाद को बढ़ाएगा। हालाँकि यह सभी ऑपरेशनों के व्यवहार को बदल देता है, इसलिए यह व्यवहार में एक बहुत बड़ा बदलाव है।
  2. उपयोग करें numpy.seterr(all='warn'), जो वास्तविक चेतावनी में मुद्रित चेतावनी को बदल देगा और आप व्यवहार में इस परिवर्तन को स्थानीय बनाने के लिए उपरोक्त समाधान का उपयोग करने में सक्षम होंगे।

एक बार जब आपके पास वास्तव में एक चेतावनी होती है, तो आप warningsमॉड्यूल का उपयोग यह नियंत्रित करने के लिए कर सकते हैं कि चेतावनी कैसे व्यवहार की जानी चाहिए:

>>> import warnings
>>> 
>>> warnings.filterwarnings('error')
>>> 
>>> try:
...     warnings.warn(Warning())
... except Warning:
...     print 'Warning was raised as an exception!'
... 
Warning was raised as an exception!

प्रलेखन को ध्यान से पढ़ें filterwarningsक्योंकि यह आपको केवल उस चेतावनी को फ़िल्टर करने की अनुमति देता है जिसे आप चाहते हैं और अन्य विकल्प हैं। मैं यह भी देखने पर विचार करूंगा कि catch_warningsकौन सा संदर्भ प्रबंधक है जो मूल filterwarningsफ़ंक्शन को स्वचालित रूप से रीसेट करता है :

>>> import warnings
>>> with warnings.catch_warnings():
...     warnings.filterwarnings('error')
...     try:
...         warnings.warn(Warning())
...     except Warning: print 'Raised!'
... 
Raised!
>>> try:
...     warnings.warn(Warning())
... except Warning: print 'Not raised!'
... 
__main__:2: Warning: 

मुझे लगता है कि यह एक शुरुआत है। लेकिन यह वास्तव में मेरी समस्या को ठीक नहीं करता है। यदि मैं अपने कोड में चेतावनियों में warnings.warn (चेतावनी ()) जोड़ता हूं, तो यह चेतावनी को पकड़ लेगा। किसी कारण से यह शून्य चेतावनी द्वारा विभाजन को नहीं पकड़ता है। यहां सटीक चेतावनी संदेश दिया गया है: चेतावनी: int_scalars में शून्य से विभाजित करें
जॉन के।

@JohnK। आपको अपने प्रश्न को संपादित करना चाहिए और सटीक आउटपुट जोड़ना चाहिए, अन्यथा हम यह नहीं बता सकते कि क्या गलत है। यह हो सकता है संभव है कि numpy इस चेतावनी वर्ग कहीं परिभाषित करता है हो सकता है और आप जो सबपैकेज में discovere करने के लिए इसे पकड़ने के लिए सक्षम होना चाहिए। कोई बात नहीं, मैंने पाया कि आपको इसका उपयोग करना चाहिए RuntimeWarning। उत्तर अपडेट किया गया।
बकुरीउ

क्या आपको यकीन है? मैंने अपना कोड RuntimeWarning को छोड़कर उपयोग करने के लिए बदल दिया:। यह अभी भी काम नहीं कर रहा है = /
जॉन के।

@JohnK। प्रलेखन में यह कहा गया है कि एक RuntimeWarningउठाया जाता है। समस्या यह हो सकती है कि आपका संख्यात्मक कॉन्फ़िगरेशन printविकल्प का उपयोग कर रहा है, जो बस चेतावनी को प्रिंट करता है लेकिन यह warningsमॉड्यूल द्वारा नियंत्रित वास्तविक चेतावनी नहीं है ... यदि यह मामला है तो आप उपयोग करने numpy.seterr(all='warn')और फिर से प्रयास करने का प्रयास कर सकते हैं ।
बकुरीउ

3
मेरे संस्करण में numpy, आप का उपयोग नहीं कर सकते हैं numpy.seterr(all='error'), की errorजरूरत है raise
detly

41

@ बकुरीउ के उत्तर में थोड़ा जोड़ने के लिए:

यदि आप पहले से ही जानते हैं कि चेतावनी कहां होने की संभावना है, तो numpy.errstateसंदर्भ प्रबंधक का उपयोग करने के लिए अक्सर क्लीनर होता है, numpy.seterrजिसके बजाय उसी तरह की सभी बाद की चेतावनियों का इलाज करता है , भले ही वे आपके कोड में हों, जहां भी हो।

import numpy as np

a = np.r_[1.]
with np.errstate(divide='raise'):
    try:
        a / 0   # this gets caught and handled as an exception
    except FloatingPointError:
        print('oh no!')
a / 0           # this prints a RuntimeWarning as usual

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

मेरे मूल उदाहरण में मेरे पास था a = np.r_[0], लेकिन जाहिर तौर पर स्तूप के व्यवहार में बदलाव था जैसे कि विभाजन-शून्य को उन मामलों में अलग तरीके से संभाला जाता है जहां अंश सभी शून्य हैं। उदाहरण के लिए, सुकुमार 1.16.4 में:

all_zeros = np.array([0., 0.])
not_all_zeros = np.array([1., 0.])

with np.errstate(divide='raise'):
    not_all_zeros / 0.  # Raises FloatingPointError

with np.errstate(divide='raise'):
    all_zeros / 0.  # No exception raised

with np.errstate(invalid='raise'):
    all_zeros / 0.  # Raises FloatingPointError

संबंधित चेतावनी संदेश भी भिन्न हैं: के 1. / 0.रूप में लॉग किया गया है RuntimeWarning: divide by zero encountered in true_divide, जबकि 0. / 0.लॉग किया गया है RuntimeWarning: invalid value encountered in true_divide। मुझे यकीन नहीं है कि वास्तव में यह परिवर्तन क्यों किया गया था, लेकिन मुझे संदेह है कि इसका इस तथ्य के साथ क्या करना है कि 0. / 0.एक संख्या के रूप में प्रतिनिधित्व करने योग्य परिणाम नहीं है (इस मामले में एक खामियाजा NaN लौटाता है) जबकि 1. / 0.और -1. / 0.वापसी + Inf और -Inf , IEE 754 मानक के अनुसार।

यदि आप दोनों प्रकार की त्रुटि पकड़ना चाहते हैं तो आप हमेशा पास हो सकते हैं np.errstate(divide='raise', invalid='raise'), या all='raise'यदि आप किसी भी प्रकार की फ़्लोटिंग पॉइंट त्रुटि पर अपवाद उठाना चाहते हैं ।


विशेष रूप से यह उठता है FloatingPointError, नहीं ZeroDivisionError
gerrit

इस पर काम नहीं करता Python 3.6.3साथ numpy==1.16.3। क्या आप कृपया इसे अपडेट कर सकते हैं?
अनिलबाई

1
@anilbey जाहिरा तौर पर सुन्न के व्यवहार में एक बदलाव था जिसका अर्थ है कि डिवीजन-बाय-ज़ीरो अब अलग-अलग तरीके से संभाला जाता है जो इस बात पर निर्भर करता है कि अंश भी (सभी) शून्य है।
अली_म

27

ऊपर @ बकुरीउ के जवाब पर विस्तार से बताने के लिए, मैंने पाया है कि यह मुझे इसी तरह से एक रनटाइम चेतावनी को पकड़ने में सक्षम बनाता है कि मैं एक त्रुटि चेतावनी कैसे पकड़ूंगा, चेतावनी को अच्छी तरह से प्रिंट कर रहा हूं:

import warnings

with warnings.catch_warnings():
    warnings.filterwarnings('error')
    try:
        answer = 1 / 0
    except Warning as e:
        print('error found:', e)

आप शायद चेतावनियों को रखने में सक्षम होंगे। इस तरह से त्रुटियों को पकड़ने के साथ आप कितना बड़ा छत्र लगाना चाहते हैं, इस पर निर्भर करता है।


3
उत्तर =
1/0

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