Книга: Practical Programming, Fourth Edition
Назад: Raising and Chaining Exceptions
Дальше: Exceptionally Important!

Defining Custom Exceptions

In the , choosing IOError as a replacement for FileNotFoundError is functional but not ideal. While it raises the level of abstraction from “file not found” to “input/output error,” that abstraction is still too low-level for, say, an enterprise-scale data management system.

A better approach is to define a custom exception type that reflects the problem in domain-specific terms. For example, you could define a new exception type called DataLoadError. Custom exceptions are typically subclasses of the built-in class Exception:

​ ​>>>​​ ​​class​​ ​​DataLoadError(Exception):​
​ ​...​​ ​​"""Custom exception for data loading errors."""​
​ ​...​
​ ​>>>​​ ​​help(DataLoadError)​
​ Help on class DataLoadError in module __main__:
​ 
​ class DataLoadError(builtins.Exception)
​  | Custom exception for data loading errors.
​  |
​  | Method resolution order:
​ ​...​

Inheritance Matters!

icon indicating an aside

Inherit custom exceptions from Exception, not BaseException. BaseException is for system-exiting errors.

The body of a custom exception class can be empty except for a docstring that documents its purpose (you may want to revisit ). Even this minimal definition provides two major benefits:

You can now rewrite the previous example in terms of this domain-specific exception:

​ ​>>>​​ ​​def​​ ​​load_data(filename:​​ ​​str)​​ ​​->​​ ​​str:​
​ ​...​​ ​​"""Return the contents of the file `filename`."""​
​ ​...​​ ​​try:​
​ ​...​​ ​​with​​ ​​open(filename)​​ ​​as​​ ​​infile:​
​ ​...​​ ​​return​​ ​​infile.read()​
​ ​...​​ ​​except​​ ​​FileNotFoundError​​ ​​as​​ ​​eo:​
​ ​...​​ ​​raise​​ ​​DataLoadError(f​​'Could not load data from {filename}'​​)​​ ​​from​​ ​​eo​
​ ​...​
​ ​>>>​​ ​​try:​
​ ​...​​ ​​load_data(​​'missing.txt'​​)​
​ ​...​​ ​​except​​ ​​DataLoadError​​ ​​as​​ ​​eo:​
​ ​...​​ ​​print(eo)​
​ ​...​​ ​​print(​​'Original cause: {eo.__cause__}'​​)​
​ ​...​
​ Could not load data from missing.txt
​ Original cause: [Errno 2] No such file or directory: 'missing.txt'

The functionality of the code remains the same, but its readability and maintainability improve significantly. Instead of leaking low-level implementation details (FileNotFoundError), the function communicates a higher-level concept (DataLoadError) that better matches the language of the application or domain.

Назад: Raising and Chaining Exceptions
Дальше: Exceptionally Important!