Exception Class and Inheritance
Custom exceptions inherit from Exception and let you encode domain-specific error information as instance attributes.
Why Custom Exceptions Matter
A custom exception gives a program a named way to represent a domain-specific error. Instead of treating every failure as an undifferentiated error, you can define an exception class for a particular condition and store information about that condition on the exception object.
Suppose an inventory operation cannot fulfill a request because too few units are available. An InventoryError could carry the requested quantity and the available quantity. Code that catches the exception can then use those attributes when deciding how to respond.
The central pattern is: define a custom exception, initialize its domain-specific data, raise it when the condition occurs, and catch it with an except clause that names the exception object.
The Inheritance Relationship
A custom exception is defined by inheriting from Exception. The custom class gives the error a domain-specific name and can add instance attributes that describe the particular failure. The parent class is still important: the custom exception remains an Exception-derived error that can be used with raise and caught by an except clause.
Storing Error Details
A custom exception can encode domain-specific error information as instance attributes. Its __init__ method receives the information needed to describe one occurrence of the error, assigns that information to attributes, and calls Exception.__init__.
Always call Exception.__init__ in the custom exception's __init__ method. The custom attributes provide domain-specific information, while the parent initialization remains part of constructing the exception.
Following the Raise Path
The raise statement is the point where the program signals the specific error condition. When the condition is reached, control flow jumps immediately from raise to the first matching except block. The remaining statements in the try block are skipped.
5
3In this example, the call to withdraw raises InventoryError before return runs. The print inside the try block is therefore skipped. The except clause catches the exception as error, and error provides access to the requested and available attributes.
Reading the Caught Object
The as keyword gives the caught exception object a name inside the except block. That name refers to the custom exception instance created when the exception was raised. Its custom attributes can then be accessed using normal attribute access.
Tracing an Inventory Failure
Determine which statements run when withdraw is called with stock equal to 3 and requested equal to 5.
Check the condition: The requested quantity is greater than the stock quantity, so the specific error condition occurs.
Raise the exception: InventoryError is created with requested and available values, then raised.
Skip the remaining try statements: Control flow leaves the try block immediately, so statements after the call in that block do not run.
Bind the exception: The matching except clause binds the caught exception object to error.
Read the attributes: The handler accesses error.requested and error.available to obtain the domain-specific values.
The handler receives the custom exception object and can access both stored attributes.
Choosing Exception Handlers
Order except clauses from most specific to most general. A handler for the custom exception should appear before a more general handler so that the specific condition can be handled as intended.
Mistakes Beginners Make
Defining the custom class without inheriting from Exception
The class is not defined as a custom exception derived from Exception.
Fix:
Declare it as class InventoryError(Exception).Failing to call Exception.__init__
The custom initialization stores the domain attributes but omits the required parent initialization.
Fix:
Call Exception.__init__(self) inside the custom __init__ method.Raising without the required arguments
The custom exception's initialization requires the domain-specific arguments used to set its attributes.
Fix:
Raise it with all required arguments, such as raise InventoryError(requested, stock).Ignoring the exception object in the except clause
The handler does not bind the caught object, so it cannot access the custom attributes through a local exception name.
Fix:
Use the as keyword, such as except InventoryError as error, when the handler needs the stored attributes.Putting a general handler before a specific handler
Exception handlers should be ordered from most specific to most general.
Fix:
Place except InventoryError before except Exception.
Practice the Full Pattern
Create a custom exception named PaymentError that inherits from Exception. Give it two instance attributes, attempted and limit. Write a function that raises PaymentError when attempted is greater than limit. Then write a try-except block that catches the exception as error and accesses both custom attributes.
Hints
- Define __init__ with attempted and limit parameters.
- Assign both parameters to instance attributes.
- Call Exception.__init__(self) in __init__.
- Use raise PaymentError(attempted, limit) when the condition occurs.
- Use except PaymentError as error to access error.attempted and error.limit.
What do you think happens?
If a raise statement runs inside a try block, do statements later in that try block run before the matching except handler?
Reveal answer
Answer: No, control jumps directly to the first matching except block.
The source rule states that control flow jumps immediately from raise to the first matching except block, skipping the rest of the try block.
The Complete Pattern
- A custom exception inherits from Exception.
- Its __init__ method can store domain-specific error information as instance attributes.
- The custom __init__ method should call Exception.__init__.
- Raise the custom exception with all required arguments when its specific error condition occurs.
- Catch it with a matching except clause and the as keyword when the handler needs to access its attributes.
- Control flow leaves the try block immediately when raise runs, and except clauses should be ordered from most specific to most general.
Key Takeaways
- Custom exceptions are Exception subclasses that give domain-specific errors a clear type.
- Instance attributes let a custom exception carry information about the particular error occurrence.
- A custom exception should initialize its parent with Exception.__init__.
- raise transfers control immediately to the first matching except clause.
- The as keyword binds the caught exception object so its custom attributes can be accessed.