Path: csiph.com!usenet.pasdenom.info!gegeweb.org!de-l.enfer-du-nord.net!feeder2.enfer-du-nord.net!cs.uu.nl!news.stack.nl!newsfeed.xs4all.nl!newsfeed1.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'exception': 0.03; 'explicitly': 0.04; 'subject:Python': 0.05; 'context': 0.05; 'exception.': 0.07; 'operand': 0.07; 'try:': 0.07; 'valueerror:': 0.07; 'python': 0.09; 'exception,': 0.09; 'exception:': 0.09; 'exceptions,': 0.09; 'handler,': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'terry': 0.09; 'typeerror:': 0.09; 'url:peps': 0.09; 'def': 0.10; 'programmer': 0.11; 'index': 0.13; 'language': 0.14; 'library': 0.15; "'from": 0.16; "'int'": 0.16; '3.3,': 0.16; 'attribute,': 0.16; 'attributes:': 0.16; 'indexerror:': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'set,': 0.16; 'suppressing': 0.16; 'unsupported': 0.16; 'wrote:': 0.17; 'url:dev': 0.17; 'jan': 0.18; 'written': 0.20; '"",': 0.22; 'displayed': 0.22; 'exceptions': 0.22; 'features,': 0.22; 'occurs': 0.22; "i'd": 0.22; "python's": 0.23; 'sets': 0.23; 'raise': 0.24; 'second': 0.24; 'allows': 0.25; 'header:In-Reply- To:1': 0.25; 'header:User-Agent:1': 0.26; 'common': 0.26; '(most': 0.27; 'am,': 0.27; 'first,': 0.27; 'handling': 0.27; '2.6': 0.27; 'displays': 0.27; 'header:X-Complaints-To:1': 0.28; 'actual': 0.28; '3.1': 0.29; 'block,': 0.29; "d'aprano": 0.29; 'informative': 0.29; 'priority.': 0.29; 'statements': 0.29; 'steven': 0.29; 'probably': 0.29; 'error': 0.30; 'url:python': 0.32; 'file': 0.32; 'print': 0.32; 'message.': 0.33; 'traceback': 0.33; 'to:addr:python-list': 0.33; 'another': 0.33; 'list': 0.35; 'clear': 0.35; 'awesome': 0.35; 'sometimes': 0.35; 'there': 0.35; 'received:org': 0.36; 'except': 0.36; 'but': 0.36; 'url:org': 0.36; 'skip:p 20': 0.36; 'bad': 0.37; 'does': 0.37; 'option': 0.37; 'two': 0.37; 'subject:: ': 0.38; 'object': 0.38; 'some': 0.38; 'shows': 0.38; 'to:addr:python.org': 0.39; 'takes': 0.39; 'skip:" 10': 0.40; 'header:Received:5': 0.40; 'end': 0.40; 'easy': 0.60; 'range': 0.60; 'skip:u 10': 0.60; "you've": 0.61; 'first': 0.61; 'here:': 0.62; 'ever': 0.63; 'more': 0.63; 'decided': 0.65; 'finally': 0.66; 'direct': 0.69; 'special': 0.73; 'grow': 0.74; 'miss': 0.75; 'chapter.': 0.84; 'examples.': 0.84; 'idiom': 0.84; 'manual,': 0.84; 'received:fios.verizon.net': 0.84; 'type(s)': 0.84; 'rick': 0.91 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: Awsome Python - chained exceptions Date: Tue, 12 Feb 2013 10:13:15 -0500 References: <5119de00$0$11096$c3e8da3@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: pool-173-75-251-66.phlapa.fios.verizon.net User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130107 Thunderbird/17.0.2 In-Reply-To: <5119de00$0$11096$c3e8da3@news.astraweb.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 109 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1360682013 news.xs4all.nl 6938 [2001:888:2000:d::a6]:49285 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:38754 On 2/12/2013 1:15 AM, Steven D'Aprano wrote: > As an antidote to the ill-informed negativity of Ranting Rick's > illusionary "PyWarts", I thought I'd present a few of Python's more > awesome features, starting with exception contexts. You do not need Rick to justify such an informative post. > If you've ever written an exception handler, you've probably written a > *buggy* exception handler: > > > def getitem(items, index): > # One-based indexing. > try: > return items[index-1] > except IndexError: > print ("Item at index %d is missing" % index - 1) # Oops! > > > Unfortunately, when an exception occurs inside an except or finally > block, the second exception masks the first, and the reason for the > original exception is lost: > > py> getitem(['one', 'two', 'three'], 5) # Python 2.6 > Traceback (most recent call last): > File "", line 1, in > File "", line 6, in getitem > TypeError: unsupported operand type(s) for -: 'str' and 'int' > > > But never fear! In Python 3.1 and better, Python now shows you the full > chain of multiple exceptions, and exceptions grow two new special > attributes: __cause__ and __context__. Some thought was given to having only one special attribute, but in the end it was decided to have __context__ be the actual context and __cause__ be the programmer set and displayed 'context'. > If an exception occurs while handling another exception, Python sets the > exception's __context__ and displays an extended error message: > > py> getitem(['one', 'two', 'three'], 5) # Python 3.1 > Traceback (most recent call last): > File "", line 4, in getitem > IndexError: list index out of range > > During handling of the above exception, another exception occurred: > > Traceback (most recent call last): > File "", line 1, in > File "", line 6, in getitem > TypeError: unsupported operand type(s) for -: 'str' and 'int' > > Python 3 also allows you to explicitly set the exception's __cause__ > using "raise...from" syntax: > > py> try: > ... len(None) > ... except TypeError as e: > ... raise ValueError('bad value') from e > ... > Traceback (most recent call last): > File "", line 2, in > TypeError: object of type 'NoneType' has no len() > > The above exception was the direct cause of the following exception: > > Traceback (most recent call last): > File "", line 4, in > ValueError: bad value > > Note the slight difference in error message. If both __cause__ and > __context__ are set, the __cause__ takes priority. > > Sometimes you actually want to deliberately catch one exception and raise > another, without showing the first exception. A very common idiom in > Python 2: > > try: > do_work() > except SomeInternalError: > raise PublicError(error_message) > > Starting with Python 3.3, there is now support from intentionally > suppressing the __context__: > > py> try: > ... len(None) > ... except TypeError: > ... raise ValueError('bad value') from None # Python 3.3 > ... > Traceback (most recent call last): > File "", line 4, in > ValueError: bad value > The new features are explained in the Library manual, Ch. 5, Exceptions, but without so many clear examples. The 'from None' option has not yet been added to the Language reference section on raise statements (an issue on the tracker), so it is easy to miss if one does not also read the Library chapter. > > You can read more about exception chaining here: > > http://www.python.org/dev/peps/pep-3134/ > http://www.python.org/dev/peps/pep-0409/ -- Terry Jan Reedy