Here are some ideas:
(0) Explain «a file» and «occasionally»: do you really mean it works sometimes and fails sometimes with the same file?
Do the following for each failing file:
(1) Find out what is in the file at the point that it is complaining about:
text = open("the_file.xml", "rb").read()
err_col = 52459
print repr(text[err_col-50:err_col+100]) # should include the error text
print repr(text[:50]) # show the XML declaration
(2) Throw your file at a web-based XML validation service e.g. http://www.validome.org/xml/ or http://validator.aborla.net/
and edit your question to display your findings.
Update: Here is the minimal xml file that illustrates your problem:
[badcharref.xml]
<a></a>
[Python 2.7.1 output]
>>> import xml.etree.ElementTree as ET
>>> it = ET.iterparse(file("badcharref.xml"))
>>> for ev, el in it:
... print el.tag
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:python27libxmletreeElementTree.py", line 1258, in next
self._parser.feed(data)
File "C:python27libxmletreeElementTree.py", line 1624, in feed
self._raiseerror(v)
File "C:python27libxmletreeElementTree.py", line 1488, in _raiseerror
raise err
xml.etree.ElementTree.ParseError: reference to invalid character number: line 1, column 3
>>>
Not all valid Unicode characters are valid in XML. See the XML 1.0 Specification.
You may wish to examine your files using regexes like r'&#([0-9]+);'
and r'&#x([0-9A-Fa-f]+);'
, convert the matched text to an int ordinal and check against the valid list from the spec i.e. #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
… or maybe the numeric character reference is syntactically invalid e.g. not terminated by a ;
‘, &#not-a-digit
etc etc
Update 2 I was wrong, the number in the ElementTree error message is counting Unicode code points, not bytes. See the code below and snippets from the output from running it over the two bad files.
# coding: ascii
# Find numeric character references that refer to Unicode code points
# that are not valid in XML.
# Get byte offsets for seeking etc in undecoded file bytestreams.
# Get unicode offsets for checking against ElementTree error message,
# **IF** your input file is small enough.
BYTE_OFFSETS = True
import sys, re, codecs
fname = sys.argv[1]
print fname
if BYTE_OFFSETS:
text = open(fname, "rb").read()
else:
# Assumes file is encoded in UTF-8.
text = codecs.open(fname, "rb", "utf8").read()
rx = re.compile("&#([0-9]+);|&#x([0-9a-fA-F]+);")
endpos = len(text)
pos = 0
while pos < endpos:
m = rx.search(text, pos)
if not m: break
mstart, mend = m.span()
target = m.group(1)
if target:
num = int(target)
else:
num = int(m.group(2), 16)
# #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
if not(num in (0x9, 0xA, 0xD) or 0x20 <= num <= 0xD7FF
or 0xE000 <= num <= 0xFFFD or 0x10000 <= num <= 0x10FFFF):
print mstart, m.group()
pos = mend
Output:
comments.xml
6615405 
10205764 �
10213901 �
10213936 �
10214123 �
13292514 
...
155656543 
155656564 
157344876 
157722583 
posts.xml
7607143 
12982273 
12982282 
12982292 
12982302 
12982310 
16085949 
16085955 
...
36303479 
36303494  <<=== whoops
38942863 
...
785292911 
801282472 
848911592 
Subsections
- 8.1 Syntax Errors
- 8.2 Exceptions
- 8.3 Handling Exceptions
- 8.4 Raising Exceptions
- 8.5 User-defined Exceptions
- 8.6 Defining Clean-up Actions
8. Errors and Exceptions
Until now error messages haven’t been more than mentioned, but if you
have tried out the examples you have probably seen some. There are
(at least) two distinguishable kinds of errors:
syntax errors and exceptions.
8.1 Syntax Errors
Syntax errors, also known as parsing errors, are perhaps the most common
kind of complaint you get while you are still learning Python:
>>> while True print 'Hello world' File "<stdin>", line 1, in ? while True print 'Hello world' ^ SyntaxError: invalid syntax
The parser repeats the offending line and displays a little `arrow’
pointing at the earliest point in the line where the error was
detected. The error is caused by (or at least detected at) the token
preceding the arrow: in the example, the error is detected at
the keyword print, since a colon («:») is missing
before it. File name and line number are printed so you know where to
look in case the input came from a script.
8.2 Exceptions
Even if a statement or expression is syntactically correct, it may
cause an error when an attempt is made to execute it.
Errors detected during execution are called exceptions and are
not unconditionally fatal: you will soon learn how to handle them in
Python programs. Most exceptions are not handled by programs,
however, and result in error messages as shown here:
>>> 10 * (1/0) Traceback (most recent call last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo by zero >>> 4 + spam*3 Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: cannot concatenate 'str' and 'int' objects
The last line of the error message indicates what happened.
Exceptions come in different types, and the type is printed as part of
the message: the types in the example are
ZeroDivisionError, NameError and
TypeError.
The string printed as the exception type is the name of the built-in
exception that occurred. This is true for all built-in
exceptions, but need not be true for user-defined exceptions (although
it is a useful convention).
Standard exception names are built-in identifiers (not reserved
keywords).
The rest of the line is a detail whose interpretation depends on the
exception type; its meaning is dependent on the exception type.
The preceding part of the error message shows the context where the
exception happened, in the form of a stack backtrace.
In general it contains a stack backtrace listing source lines; however,
it will not display lines read from standard input.
The Python Library
Reference lists the built-in exceptions and their meanings.
8.3 Handling Exceptions
It is possible to write programs that handle selected exceptions.
Look at the following example, which asks the user for input until a
valid integer has been entered, but allows the user to interrupt the
program (using Control-C or whatever the operating system
supports); note that a user-generated interruption is signalled by
raising the KeyboardInterrupt exception.
>>> while True: ... try: ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: ... print "Oops! That was no valid number. Try again..." ...
The try statement works as follows.
- First, the try clause (the statement(s) between the
try and except keywords) is executed. - If no exception occurs, the except clause is skipped and
execution of the try statement is finished. - If an exception occurs during execution of the try clause, the rest of
the clause is skipped. Then if its type matches the exception named
after the except keyword, the rest of the try clause is
skipped, the except clause is executed, and then execution continues
after the try statement. - If an exception occurs which does not match the exception named in the
except clause, it is passed on to outer try statements; if
no handler is found, it is an unhandled exception and execution
stops with a message as shown above.
A try statement may have more than one except clause, to
specify handlers for different exceptions. At most one handler will
be executed. Handlers only handle exceptions that occur in the
corresponding try clause, not in other handlers of the same
try statement. An except clause may name multiple exceptions
as a parenthesized list, for example:
... except (RuntimeError, TypeError, NameError): ... pass
The last except clause may omit the exception name(s), to serve as a
wildcard. Use this with extreme caution, since it is easy to mask a
real programming error in this way! It can also be used to print an
error message and then re-raise the exception (allowing a caller to
handle the exception as well):
import sys try: f = open('myfile.txt') s = f.readline() i = int(s.strip()) except IOError, (errno, strerror): print "I/O error(%s): %s" % (errno, strerror) except ValueError: print "Could not convert data to an integer." except: print "Unexpected error:", sys.exc_info()[0] raise
The try … except statement has an optional
else clause, which, when present, must follow all except
clauses. It is useful for code that must be executed if the try
clause does not raise an exception. For example:
for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print 'cannot open', arg else: print arg, 'has', len(f.readlines()), 'lines' f.close()
The use of the else clause is better than adding additional
code to the try clause because it avoids accidentally
catching an exception that wasn’t raised by the code being protected
by the try … except statement.
When an exception occurs, it may have an associated value, also known as
the exception’s argument.
The presence and type of the argument depend on the exception type.
The except clause may specify a variable after the exception name (or list).
The variable is bound to an exception instance with the arguments stored
in instance.args
. For convenience, the exception instance
defines __getitem__ and __str__ so the arguments can
be accessed or printed directly without having to reference .args
.
>>> try: ... raise Exception('spam', 'eggs') ... except Exception, inst: ... print type(inst) # the exception instance ... print inst.args # arguments stored in .args ... print inst # __str__ allows args to printed directly ... x, y = inst # __getitem__ allows args to be unpacked directly ... print 'x =', x ... print 'y =', y ... <type 'instance'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
If an exception has an argument, it is printed as the last part
(`detail’) of the message for unhandled exceptions.
Exception handlers don’t just handle exceptions if they occur
immediately in the try clause, but also if they occur inside functions
that are called (even indirectly) in the try clause.
For example:
>>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError, detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo
8.4 Raising Exceptions
The raise statement allows the programmer to force a
specified exception to occur.
For example:
>>> raise NameError, 'HiThere' Traceback (most recent call last): File "<stdin>", line 1, in ? NameError: HiThere
The first argument to raise names the exception to be
raised. The optional second argument specifies the exception’s
argument.
If you need to determine whether an exception was raised but don’t
intend to handle it, a simpler form of the raise statement
allows you to re-raise the exception:
>>> try: ... raise NameError, 'HiThere' ... except NameError: ... print 'An exception flew by!' ... raise ... An exception flew by! Traceback (most recent call last): File "<stdin>", line 2, in ? NameError: HiThere
8.5 User-defined Exceptions
Programs may name their own exceptions by creating a new exception
class. Exceptions should typically be derived from the
Exception class, either directly or indirectly. For
example:
>>> class MyError(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MyError(2*2) ... except MyError, e: ... print 'My exception occurred, value:', e.value ... My exception occurred, value: 4 >>> raise MyError, 'oops!' Traceback (most recent call last): File "<stdin>", line 1, in ? __main__.MyError: 'oops!'
Exception classes can be defined which do anything any other class can
do, but are usually kept simple, often only offering a number of
attributes that allow information about the error to be extracted by
handlers for the exception. When creating a module which can raise
several distinct errors, a common practice is to create a base class
for exceptions defined by that module, and subclass that to create
specific exception classes for different error conditions:
class Error(Exception): """Base class for exceptions in this module.""" pass class InputError(Error): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ def __init__(self, expression, message): self.expression = expression self.message = message class TransitionError(Error): """Raised when an operation attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ def __init__(self, previous, next, message): self.previous = previous self.next = next self.message = message
Most exceptions are defined with names that end in «Error,» similar
to the naming of the standard exceptions.
Many standard modules define their own exceptions to report errors
that may occur in functions they define. More information on classes
is presented in chapter 9, «Classes.»
8.6 Defining Clean-up Actions
The try statement has another optional clause which is
intended to define clean-up actions that must be executed under all
circumstances. For example:
>>> try: ... raise KeyboardInterrupt ... finally: ... print 'Goodbye, world!' ... Goodbye, world! Traceback (most recent call last): File "<stdin>", line 2, in ? KeyboardInterrupt
A finally clause is executed whether or not an exception has
occurred in the try clause. When an exception has occurred, it is
re-raised after the finally clause is executed. The finally clause is
also executed «on the way out» when the try statement is
left via a break or return statement.
The code in the finally clause is useful for releasing external
resources (such as files or network connections), regardless of
whether or not the use of the resource was successful.
A try statement must either have one or more except clauses
or one finally clause, but not both.
Release 2.4, documentation updated on 29 November 2004.
Python Errors and Exceptions | Python 3 Exception Handling Tutorial For Beginners 2018. Here in this blog post Coding compiler sharing Python 3 Errors and Exceptions tutorial for beginners. You will learn about Python exception handling as well. This Python tutorial is for beginners and intermediate learners who are looking to master in Python programming. Experienced Python programmers also can refer this tutorial to brush-up their Python 3 programming skills. Let’s start learning Python 3.
There has been no further discussion of error messages so far, but you may have already encountered some of the examples you have experimented with. There are (at least) two kinds of errors in Python: syntax errors and exceptions ( syntax errors and exceptions ).
Python Errors and Exceptions Tutorial | |
1. Grammatical errors | 5. User-defined exceptions |
2. Exceptions | 6. Defining Cleanup Behavior |
3. Exception Handling | 7. Predefined Cleanup Behavior |
4. Throwing an exception | 8. Python Errors and Exceptions Conclusion |
Related Articles: Python Getting Started Guide | Introduction to Python
1. Grammatical errors
Grammatical errors, also known as parsing errors, are probably the most common complaints you have while learning Python:
>>> the while True Print ( 'the Hello world' ) ? File "<stdin>", Line 1, in the while True Print ( 'the Hello world') ^ SyntaxError: invalid syntax
The parser indicates the wrong line and displays a small “arrow” in front of where the error was detected. Error is indicated by the arrow in front of (or at least so detected) caused marked: in this example, the function print () was found to errors, because the less a colon in front of it ( ':'
). The error will output the file name and line number, so if you input from a script you know where to go to check for errors.
2. Exceptions
Even if a statement or expression is syntactically correct, it may throw an error when it tries to execute it. Run-time detected errors known as anomalies , and the program will not unconditional collapse: Soon, you will learn how to handle them in Python programs.
However, most of the exceptions are not processed by the program and will eventually produce an error message as shown here:
>>> 10 * ( 1 / 0 ) Traceback (most recent call last): File "<stdin>" , line 1 , in ? ZeroDivisionError : int division or modulo by zero >>> 4 + spam * 3 Traceback (most recent Call last): File "<stdin>" , line 1 , in ? NameError : name 'spam' is not defined >>> '2' + 2 Traceback (most recent call last): File "<Stdin>" , line1 , in ? TypeError : Can't convert 'int' object to str implicitly
The last line of the error message indicates what went wrong. Exceptions also have different types. Exception types are shown as part of the error message: The exceptions in the example are ZeroDivisionError , NameError , and TypeError . When an error message is printed, the type of the exception is displayed as an abnormal built-in name.
This is true for all built-in exceptions, but user-defined exceptions are not (although this is a very useful convention). The standard exception name is a built-in ID (no reserved keywords).
This part of the line is a detailed description of the type of exception, which means that its content depends on the type of exception.
The first half of the error message lists the location of the exception in a stack. The source code line is usually listed in the stack, however, the source code from the standard input is not displayed.
Related Article: Python Interpreter Tutorial
3. Exception Handling
It is feasible to program selected exceptions through programming. Look at the following example: It will always require user input until enter a valid integer, but allows the user to interrupt the program (using Control-C
or any method supported by the system).
Note: A user generated interrupt will raise a Keyboard Interrupt exception.
>>> while True : ... try : ... x = int ( input ( "Please enter a number: " )) ... break ... except ValueError : ... print ( "Oops! That was no Valid number. Try again..." ) ...
The try statement works as follows.
-
First, execute the try clause ( the part between the try and except keywords).
-
If no exception occurs, the except clause is ignored after the try statement is executed.
-
If an exception occurs during the execution of the try clause, the rest of the clause is ignored.
If the exception matches the type of exception specified after the except keyword, the corresponding except clause is executed. Then continue with the code after the try statement.
-
If an exception occurs , there is no matching branch in the except clause, and it is passed to the previous try statement.
If you still can not find the corresponding final statement processing, it becomes a unhandled exception and execution stops with a message as shown.
A try statement may contain more than one except clauses that specify different handling of exceptions. At most only one branch will be executed. Exception handlers only handle exceptions that occur in the corresponding try clause.
In the same try statement, exceptions that occur in other clauses are not processed. An except clause can list multiple exception names in parentheses, for example:
... except ( RuntimeError , TypeError , NameError ): ... pass
The last except clause can omit the exception name for use as a wildcard. You need to use this method with caution because it will easily hide an actual program error!
You can use this method to print an error message and then re throw the exception (allowing the caller to handle this exception):
Import sys Try : f = open ( 'myfile.txt' ) s = f . readline () i = int ( s . strip ()) except OSError as err : print ( "OS error: {0} " . format ( err )) Except ValueError : print ( "Could not convert data to an integer." ) except : print ( "Unexpected error:" , SYS . exc_info () [ 0 ]) The raise
A try … except statement can have an else clause that can only appear after all except clauses. When the try statement does not throw an exception, some code needs to be executed and this clause can be used. E.g:
for Arg in SYS . the argv [ . 1 :]: the try : F = Open ( Arg , 'R & lt' ) the except IOError : Print ( 'CAN Not Open' , Arg ) the else : Print ( Arg , 'has' , len ( F . the readlines ()), 'Lines' ) F . Close ()
It is better to use the else clause than to append the code in the try clause, because this avoids try … except accidentally intercepting exceptions thrown by those code that are not protected by them.
When an exception occurs, it may have an associated value, as abnormal parameters exist. Whether this parameter exists or not, depends on the type of the exception.
You can also specify a variable for the except clause after the exception name (list). The variable is bound to an exception instance, it is stored in instance.args
a parameter.
For convenience, the exception instance defines __str__() so that the print parameters can be accessed directly without reference .args
. This practice is not encouraged.
Related Articles: Learn Python In One Day
Instead, it is better to pass an argument to the exception (if you pass multiple arguments, you can pass a tuple) and bind it to the message attribute. Once an exception occurs, it binds all the specified attributes before throwing it.
>>> try : ... raise Exception ( 'spam' , 'eggs' ) ... except Exception as inst : ... print ( type ( inst )) # the exception instance ... print ( inst . args ) # arguments stored in .args ... print ( inst ) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses ... x , y = inst . args # unpack args ... print ( 'x =' , x ) ... print ( 'y =' , y ) ... <class 'Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
For those unhandled exceptions, if one of them has parameters, it will be printed as the last part of the exception information (“details”).
Exception handlers not only handle exceptions that occur immediately in the try clause, they also handle exceptions that occur inside functions called in those try clauses. E.g:
>>> def this_fails (): ... x = 1 / 0 ... >>> try : ... this_fails () ... except ZeroDivisionError as err : ... print ( 'Handling run-time error: ' , err ) ... Handling run-time error: int division or modulo by zero
Related Article: Python For Machine Learning
4. Throwing an exception
The raise statement allows the programmer to force throw a specified exception. E.g:
>>> raise NameError ( 'HiThere' ) Traceback (most recent call last): File "<stdin>" , line 1 , in ? NameError : HiThere
The exception to be thrown is identified by the raise ‘s unique parameter. It must be an exception instance or an exception class (class inherited from Exception ).
If you need to specify whether an exception was thrown, but do not want to deal with it, the raise statement allows you to simply re-throw the exception:
>>> try : ... raise NameError ( 'HiThere' ) ... except NameError : ... print ( 'An exception flew by!' ) ... raise ... An exception flew by! Traceback (most recent Call last): File "<stdin>" , line 2 , in ? NameError : HiThere
5. User-defined exceptions
Programs may name their own exceptions by creating a new exception type (content type, see the Python class ). Exception classes should usually be derived directly or indirectly from the Exception class, for example:
>>> class MyError ( Exception ): ... def __init__ ( self , value ): ... self . value = value ... def __str__ ( self ): ... return repr ( self . value ) ... >>> try : ... raise MyError ( 2 * 2 ) ... except MyError as e : ... print ( 'My exception occurred, value:' , e . value ) ... My exception occurred, value: 4 >>> raise MyError ( 'oops!' ) Traceback (most recent call last): File "< Stdin>" , line 1 , in ? __main__.MyError : 'oops!'
In this example, Exception’s default __init__() is overridden. The new way simply creates the value attribute. This replaces the original way to create args properties.
An exception class can define anything that can be defined in any other class, but generally it is only for the sake of simplicity that only a few attribute information is added to it, so that an exception handling handle can be extracted.
Related Article: Python Data Structures
If a newly created module needs to throw several different kinds of errors, a common practice is to define an exception base class for the module, and then derive the corresponding exception subclass for different types of errors:
Class Error ( Exception ): """Base class for exceptions in this module.""" pass Class InputError ( Error ): """Exception raised for errors in the input. Attributes: expression -- input expression in which the error occurred message -- explanation of the error """ Def __init__ ( self , expression , message ): self . expression = expression self . message = message Class TransitionError ( Error ): """Raised when an operations attempts a state transition that's not allowed. Attributes: previous -- state at beginning of transition next -- attempted new state message -- explanation of why the specific transition is not allowed """ Def __init__ ( self , previous , next , message ): self . previous = previous self . next = next self . message = message
Similar to standard exceptions, most exceptions are named with an “Error”.
Many of the standard modules have their own exceptions defined to report possible errors in the functions they define.
Related Article: Python Modules
6. Defining Cleanup Behavior
The try statement has another optional clause that aims to define the functions that must be performed under any circumstances. E.g:
>>> try : ... raise KeyboardInterrupt ... finally : ... print ( 'Goodbye, world!' ) ... Goodbye, world! KeyboardInterrupt Traceback (most recent call last): File "<stdin>" , Line 2 , in ?
The finally clause must be executed after the program leaves the try whether or not an exception occurs . When try occurs not statements except exception trapping (or it happens except or else clause), the finally clause is executed after it is re-thrown.
The try statement exits via the break , continue, or return statement will also execute the finally clause. The following is a more complicated example:
>>> def divide ( x , y ): ... try : ... result = x / y ... except ZeroDivisionError : ... print ( "division by zero!" ) ... else : ... Print ( "result is" , result ) ... finally : ... print ( "executing finally clause" ) ... >>> divide ( 2 , 1 ) result is 2 executing finally clause >>> divide ( 2 , 0 ) division by zero! executing finally clause >>> divide ( "2" , "1" ) executing finally clause Traceback (most recent call last): File " <stdin>" , line 1 , in ? File "<stdin>" , line 3 , in divide TypeError : unsupported operand type(s) for /: 'str' and 'str'
As you can see, the finally clause executes under any circumstances. The TypeError is thrown when two strings are divided and is not caught by the except clause, so it is re-throwed after the finally clause is executed.
In a real-world application, the finally clause is used to free external resources (files or network connections, etc.) regardless of whether they are in use or not.
Related Article: Python Input and Output
7. Predefined Cleanup Behavior
Some objects define a standard cleanup behavior, which will work regardless of whether the object is successful or not. The following example attempts to open the file and print the content to the screen.
For line in open ( "myfile.txt" ): print ( line )
The problem with this code is that the open file is not closed immediately after the code is executed. This is nothing in simple scripts, but large applications can be problematic. The with statement makes it possible to ensure that objects such as files can always be cleaned in a timely manner.
With open ( "myfile.txt" ) as f : for line in f : print ( line )
After the statement is executed, the file f will always be closed even if the error occurs when the data in the file is processed. Whether other objects provide predefined cleanup behaviors to view their documentation.
Related Articles:
Python Interview Questions
Python Programming Interview Questions
In this article, you will learn error and exception handling in Python.
By the end of the article, you’ll know:
- How to handle exceptions using the try, except, and finally statements
- How to create a custom exception
- How to raise an exceptions
- How to use built-in exception effectively to build robust Python programs
Table of contents
- What are Exceptions?
- Why use Exception
- What are Errors?
- Syntax error
- Logical errors (Exception)
- Built-in Exceptions
- The try and except Block to Handling Exceptions
- Catching Specific Exceptions
- Handle multiple exceptions with a single except clause
- Using try with finally
- Using try with else clause
- Raising an Exceptions
- Exception Chaining
- Custom and User-defined Exceptions
- Customizing Exception Classes
- Exception Lifecycle
- Warnings
What are Exceptions?
An exception is an event that occurs during the execution of programs that disrupt the normal flow of execution (e.g., KeyError Raised when a key is not found in a dictionary.) An exception is a Python object that represents an error..
In Python, an exception is an object derives from the BaseException class that contains information about an error event that occurred within a method. Exception object contains:
- Error type (exception name)
- The state of the program when the error occurred
- An error message describes the error event.
Exception are useful to indicate different types of possible failure condition.
For example, bellow are the few standard exceptions
- FileNotFoundException
- ImportError
- RuntimeError
- NameError
- TypeError
In Python, we can throw an exception in the try block and catch it in except block.
Why use Exception
- Standardized error handling: Using built-in exceptions or creating a custom exception with a more precise name and description, you can adequately define the error event, which helps you debug the error event.
- Cleaner code: Exceptions separate the error-handling code from regular code, which helps us to maintain large code easily.
- Robust application: With the help of exceptions, we can develop a solid application, which can handle error event efficiently
- Exceptions propagation: By default, the exception propagates the call stack if you don’t catch it. For example, if any error event occurred in a nested function, you do not have to explicitly catch-and-forward it; automatically, it gets forwarded to the calling function where you can handle it.
- Different error types: Either you can use built-in exception or create your custom exception and group them by their generalized parent class, or Differentiate errors by their actual class
What are Errors?
On the other hand, An error is an action that is incorrect or inaccurate. For example, syntax error. Due to which the program fails to execute.
The errors can be broadly classified into two types:
- Syntax errors
- Logical errors
Syntax error
The syntax error occurs when we are not following the proper structure or syntax of the language. A syntax error is also known as a parsing error.
When Python parses the program and finds an incorrect statement it is known as a syntax error. When the parser found a syntax error it exits with an error message without running anything.
Common Python Syntax errors:
- Incorrect indentation
- Missing colon, comma, or brackets
- Putting keywords in the wrong place.
Example
print("Welcome to PYnative")
print("Learn Python with us..")
Output
print("Learn Python with us..")
^
IndentationError: unexpected indent
Logical errors (Exception)
Even if a statement or expression is syntactically correct, the error that occurs at the runtime is known as a Logical error or Exception. In other words, Errors detected during execution are called exceptions.
Common Python Logical errors:
- Indenting a block to the wrong level
- using the wrong variable name
- making a mistake in a boolean expression
Example
a = 10
b = 20
print("Addition:", a + c)
Output
print("Addition:", a + c)
NameError: name 'c' is not defined
Built-in Exceptions
The below table shows different built-in exceptions.
Python automatically generates many exceptions and errors. Runtime exceptions, generally a result of programming errors, such as:
- Reading a file that is not present
- Trying to read data outside the available index of a list
- Dividing an integer value by zero
Exception | Description |
---|---|
AssertionError |
Raised when an assert statement fails. |
AttributeError |
Raised when attribute assignment or reference fails. |
EOFError |
Raised when the input() function hits the end-of-file condition. |
FloatingPointError |
Raised when a floating-point operation fails. |
GeneratorExit |
Raise when a generator’s close() method is called. |
ImportError |
Raised when the imported module is not found. |
IndexError |
Raised when the index of a sequence is out of range. |
KeyError |
Raised when a key is not found in a dictionary. |
KeyboardInterrupt |
Raised when the user hits the interrupt key (Ctrl+C or Delete) |
MemoryError |
Raised when an operation runs out of memory. |
NameError |
Raised when a variable is not found in the local or global scope. |
OSError |
Raised when system operation causes system related error. |
ReferenceError |
Raised when a weak reference proxy is used to access a garbage collected referent. |
Example: The FilenotfoundError
is raised when a file in not present on the disk
fp = open("test.txt", "r")
if fp:
print("file is opened successfully")
Output:
FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
The try
and except
Block to Handling Exceptions
When an exception occurs, Python stops the program execution and generates an exception message. It is highly recommended to handle exceptions. The doubtful code that may raise an exception is called risky code.
To handle exceptions we need to use try and except block. Define risky code that can raise an exception inside the try
block and corresponding handling code inside the except
block.
Syntax
try :
# statements in try block
except :
# executed when exception occured in try block
The try block is for risky code that can raise an exception and the except block to handle error raised in a try block. For example, if we divide any number by zero, try block will throw ZeroDivisionError
, so we should handle that exception in the except block.
When we do not use try…except
block in the program, the program terminates abnormally, or it will be nongraceful termination of the program.
Now let’s see the example when we do not use try…except
block for handling exceptions.
Example:
a = 10
b = 0
c = a / b
print("a/b = %d" % c)
Output
Traceback (most recent call last):
File "E:/demos/exception.py", line 3, in <module>
c = a / b
ZeroDivisionError: division by zero
We can see in the above code when we are divided by 0; Python throws an exception as ZeroDivisionError
and the program terminated abnormally.
We can handle the above exception using the try…except
block. See the following code.
Example
try:
a = 10
b = 0
c = a/b
print("The answer of a divide by b:", c)
except:
print("Can't divide with zero. Provide different number")
Output
Can't divide with zero. Provide different number
Catching Specific Exceptions
We can also catch a specific exception. In the above example, we did not mention any specific exception in the except block. Catch all the exceptions and handle every exception is not good programming practice.
It is good practice to specify an exact exception that the except clause should catch. For example, to catch an exception that occurs when the user enters a non-numerical value instead of a number, we can catch only the built-in ValueError exception that will handle such an event properly.
We can specify which exception except
block should catch or handle. A try
block can be followed by multiple numbers of except
blocks to handle the different exceptions. But only one exception will be executed when an exception occurs.
Example
In this example, we will ask the user for the denominator value. If the user enters a number, the program will evaluate and produce the result.
If the user enters a non-numeric value then, the try block will throw a ValueError
exception, and we can catch that using a first catch block ‘except ValueError’ by printing the message ‘Entered value is wrong’.
And suppose the user enters the denominator as zero. In that case, the try block will throw a ZeroDivisionError
, and we can catch that using a second catch block by printing the message ‘Can’t divide by zero’.
try:
a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a/b
print("The answer of a divide by b:", c)
except ValueError:
print("Entered value is wrong")
except ZeroDivisionError:
print("Can't divide by zero")
Output 1:
Enter value of a:Ten Entered value is wrong
Output 2:
Enter value of a:10 Enter value of b:0 Can't divide by zero
Output 3:
Enter value of a:10 Enter value of b:2 The answer of a divide by b: 5.0
Handle multiple exceptions with a single except clause
We can also handle multiple exceptions with a single except
clause. For that, we can use an tuple
of values to specify multiple exceptions in an except
clause.
Example
Let’s see how to specifiy two exceptions in the single except clause.
try:
a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a / b
print("The answer of a divide by b:", c)
except(ValueError, ZeroDivisionError):
print("Please enter a valid value")
Using try
with finally
Python provides the finally
block, which is used with the try block statement. The finally
block is used to write a block of code that must execute, whether the try
block raises an error or not.
Mainly, the finally
block is used to release the external resource. This block provides a guarantee of execution.
Clean-up actions using finally
Sometimes we want to execute some action at any cost, even if an error occurred in a program. In Python, we can perform such actions using a finally statement with a try and except statement.
The block of code written in the finally block will always execute even there is an exception in the try and except block.
If an exception is not handled by except clause, then finally block executes first, then the exception is thrown. This process is known as clean-up action.
Syntax
try:
# block of code
# this may throw an exception
finally:
# block of code
# this will always be executed
# after the try and any except block
Example
try:
a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a / b
print("The answer of a divide by b:", c)
except ZeroDivisionError:
print("Can't divide with zero")
finally:
print("Inside a finally block")
Output 1:
Enter value of a:20 Enter value of b:5 The answer of a divide by b: 4.0 Inside a finally block
Output 2:
Enter value of a:20 Enter value of b:0 Can't divide with zero Inside a finally block
In the above example, we can see we divide a number by 0 and get an error, and the program terminates normally. In this case, the finally
block was also executed.
Using try
with else
clause
Sometimes we might want to run a specific block of code. In that case, we can use else
block with the try-except
block. The else
block will be executed if and only if there are no exception is the try
block. For these cases, we can use the optional else
statement with the try
statement.
Why to use else
block with try?
Use else statemen with try block to check if try block executed without any exception or if you want to run a specific code only if an exception is not raised
Syntax
try:
# block of code
except Exception1:
# block of code
else:
# this code executes when exceptions not occured
try
: Thetry
block for risky code that can throw an exception.except
: Theexcept
block to handle error raised in atry
block.else
: Theelse
block is executed if there is no exception.
Example
try:
a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a / b
print("a/b = %d" % c)
except ZeroDivisionError:
print("Can't divide by zero")
else:
print("We are in else block ")
Output 1
Enter value of a: 20 Enter value of b:4 a/b = 5 We are in else block
Output 2
Enter value of a: 20 Enter value of b:0 Can't divide by zero
Raising an Exceptions
In Python, the raise
statement allows us to throw an exception. The single arguments in the raise
statement show an exception to be raised. This can be either an exception object or an Exception
class that is derived from the Exception
class.
The raise
statement is useful in situations where we need to raise an exception to the caller program. We can raise exceptions in cases such as wrong data received or any validation failure.
Follow the below steps to raise an exception:
- Create an exception of the appropriate type. Use the existing built-in exceptions or create your won exception as per the requirement.
- Pass the appropriate data while raising an exception.
- Execute a raise statement, by providing the exception class.
The syntax to use the raise
statement is given below.
raise Exception_class,<value>
Example
In this example, we will throw an exception if interest rate is greater than 100.
def simple_interest(amount, year, rate):
try:
if rate > 100:
raise ValueError(rate)
interest = (amount * year * rate) / 100
print('The Simple Interest is', interest)
return interest
except ValueError:
print('interest rate is out of range', rate)
print('Case 1')
simple_interest(800, 6, 8)
print('Case 2')
simple_interest(800, 6, 800)
Output:
Case 1 The Simple Interest is 384.0 Case 2 interest rate is out of range 800
Exception Chaining
The exception chaining is available only in Python 3. The raise
statements allow us as optional from
statement, which enables chaining exceptions. So we can implement exception chaining in python3 by using raise…from
clause to chain exception.
When exception raise, exception chaining happens automatically. The exception can be raised inside except
or finally
block section. We also disabled exception chaining by using from None
idiom.
Example
try:
a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a/b
print("The answer of a divide by b:", c)
except ZeroDivisionError as e:
raise ValueError("Division failed") from e
# Output: Enter value of a:10
# Enter value of b:0
# ValueError: Division failed
In the above example, we use exception chaining using raise...from
clause and raise ValueError
division failed.
Custom and User-defined Exceptions
Sometimes we have to define and raise
exceptions explicitly to indicate that something goes wrong. Such a type of exception is called a user-defined exception or customized exception.
The user can define custom exceptions by creating a new class. This new exception class has to derive either directly or indirectly from the built-in class Exception
. In Python, most of the built-in exceptions also derived from the Exception
class.
class Error(Exception):
"""Base class for other exceptions"""
pass
class ValueTooSmallError(Error):
"""Raised when the input value is small"""
pass
class ValueTooLargeError(Error):
"""Raised when the input value is large"""
pass
while(True):
try:
num = int(input("Enter any value in 10 to 50 range: "))
if num < 10:
raise ValueTooSmallError
elif num > 50:
raise ValueTooLargeError
break
except ValueTooSmallError:
print("Value is below range..try again")
except ValueTooLargeError:
print("value out of range...try again")
print("Great! value in correct range.")
Output
Enter any value in 10 to 50 range: 5
Value is below range..try again
Enter any value in 10 to 50 range: 60
value out of range...try again
Enter any value in 10 to 50 range: 11
Great! value in correct range.
In the above example, we create two custom classes or user-defined classes with names, ValueTooSmallError
and ValueTooLargeError
.When the entered value is below the range, it will raise ValueTooSmallError
and if the value is out of then, it will raise
ValueTooLargeError
.
Customizing Exception Classes
We can customize the classes by accepting arguments as per our requirements. Any custom exception class must be Extending from BaseException
class or subclass of BaseException
.
In the above example, we create a custom class that is inherited from the base class Exception
. This class takes one argument age. When entered age is negative, it will raise NegativeAgeError
.
class NegativeAgeError(Exception):
def __init__(self, age, ):
message = "Age should not be negative"
self.age = age
self.message = message
age = int(input("Enter age: "))
if age < 0:
raise NegativeAgeError(age)
# Output:
# raise NegativeAgeError(age)
# __main__.NegativeAgeError: -9
Output:
Enter age: -28 Traceback (most recent call last): File "E:/demos/exception.py", line 11, in raise NegativeAgeError(age) main.NegativeAgeError: -28
Done
Exception Lifecycle
- When an exception is raised, The runtime system attempts to find a handler for the exception by backtracking the ordered list of methods calls. This is known as the call stack.
- If a handler is found (i.e., if
except
block is located), there are two cases in theexcept
block; either exception is handled or possibly re-thrown. - If the handler is not found (the runtime backtracks to the method chain’s last calling method), the exception stack trace is printed to the standard error console, and the application stops its execution.
Example
def sum_of_list(numbers):
return sum(numbers)
def average(sum, n):
# ZeroDivisionError if list is empty
return sum / n
def final_data(data):
for item in data:
print("Average:", average(sum_of_list(item), len(item)))
list1 = [10, 20, 30, 40, 50]
list2 = [100, 200, 300, 400, 500]
# empty list
list3 = []
lists = [list1, list2, list3]
final_data(lists)
Output
Average: 30.0 Traceback (most recent call last): File "E:/demos/exceptions.py", line 17, in final_data(lists) File "E:/demos/exceptions.py", line 11, in final_data print("Average:", average(sum_of_list(item), len(item))) Average: 300.0 File "E:/demos/exceptions.py", line 6, in average return sum / n ZeroDivisionError: division by zero
The above stack trace shows the methods that are being called from main() until the method created an exception condition. It also shows line numbers.
Warnings
Several built-in exceptions represent warning categories. This categorization is helpful to be able to filter out groups of warnings.
The warning doesn’t stop the execution of a program it indicates the possible improvement
Below is the list of warning exception
Waring Class | Meaning |
---|---|
Warning | Base class for warning categories |
UserWarning | Base class for warnings generated by user code |
DeprecationWarning | Warnings about deprecated features |
PendingDeprecationWarning | Warnings about features that are obsolete and expected to be deprecated in the future, but are not deprecated at the moment. |
SyntaxWarning | Warnings about dubious syntax |
RuntimeWarning | Warnings about the dubious runtime behavior |
FutureWarning | Warnings about probable mistakes in module imports |
ImportWarning | Warnings about probable mistakes in module imports |
UnicodeWarning | Warnings related to Unicode data |
BytesWarning | Warnings related to bytes and bytearray. |
ResourceWarning | Warnings related to resource usage |