Reputation: 309
I'm looking for a sound and practical approach to storing different errors and/or exceptions (i.e. IOError
, ValueError
, <CustomError>
, etc.) inside a class instance, but refraining from raise
-ing them straight away.
Instead I'd like to somehow communicate them to the script that import
-ed and created the class instance in the first place, and raise
the errors and exceptions there.
I'm not looking for a strategy on how to catch exceptions. For my custom exceptions, I use classes!
Is there a general approach for this?
Thanks.
Upvotes: 1
Views: 1487
Reputation: 5329
You can define a "container/collector" class which contains your custom exceptions (Of course, without raising). This collector call in my example is the MyExceptions
class.
You can define an unique exception as a class which is inherited from the related built-in exception. You can find the build-in exceptions and the exception structure (bottom of page) on this page: https://docs.python.org/2/library/exceptions.html
The basic syntax of an unique exception:
class MyException1(BaseException):
"""
Exception is inherited from 'BaseException'.
"""
def __str__(self):
return "This is my Exception1. Inherited from 'BaseException'"
You can set the message of the exception with the __str__
or the __repr__
magic methods (I have used the __str__
in my example). It means, in the above example if you raise the MyException1
exception then the message in the traceback will be This is my Exception1. Inherited from 'BaseException'
. You can read more about these magic methods on the following page: https://stackoverflow.com/a/2626364/11502612
my_exceptions.py:
class MyExceptions(object):
"""
Collector class of Unique Exceptions
"""
class MyException1(BaseException):
"""
Exception is inherited from 'BaseException'.
"""
def __str__(self):
return "This is my Exception1. Inherited from 'BaseException'"
class MyException2(Exception):
"""
Exception is inherited from 'Exception'.
"""
def __str__(self):
return "This is my Exception2. Inherited from 'Exception'"
class MyValueError(ValueError):
"""
Exception is inherited from 'ValueError'.
"""
def __str__(self):
return "This is my MyValueError. Inherited from 'ValueError'"
class AttributeError(BaseException):
"""
Redefined 'AttributeError'. Inherited from 'ValueError'
"""
def __str__(self):
return "Redefined 'AttributeError'. Inherited from 'ValueError'"
As you can see above my exception collector class is the MyExceptions
. This class contains other classes and actually these are the unique exceptions. I have written more type of exceptions. The unique exceptions are inherited from different build-in exceptions and the last one shows how you can re-defined a built-in exception (more-or-less).
Usage of these exceptions (test.py):
import my_exceptions
def raise_my_exception1():
raise my_exceptions.MyExceptions.MyException1
def raise_my_exception2():
raise my_exceptions.MyExceptions.MyException2
def raise_my_value_error():
raise my_exceptions.MyExceptions.MyValueError
def raise_my_attribute_error():
raise my_exceptions.MyExceptions.AttributeError
def raise_original_attribute_error():
raise AttributeError("This is the original (built-in) AttributeError exception")
function_list = [
raise_my_exception1,
raise_my_exception2,
raise_my_value_error,
raise_my_attribute_error,
raise_original_attribute_error,
]
for func in function_list:
try:
func()
except BaseException as e:
print(e)
As you can see in my above test.py
file, I have imported the my_exceptions.py
file as a Python module (import my_exceptions). The unique exceptions are raised in the functions. You can access the exceptions: <Module.CollectorClass.Exception>
. The last raise_original_attribute_error
function raises the built-in AttributeError
with a custom message (It shows how you can separate your own AttributeError
exception and the built-in AttributeError
). The function_list
list contains the references of the functions (With this solution I can call the function in a for loop and I don't need to call them one-by-one). In the for loop I defined a try/except
structure and call the functions. I have used the BaseException
built-in exception because it is the more wide exception in Python.
Output of the script:
>>> python2 test.py
This is my Exception1. Inherited from 'BaseException'
This is my Exception2. Inherited from 'Exception'
This is my MyValueError. Inherited from 'ValueError'
Redefined 'AttributeError'. Inherited from 'ValueError'
This is the original (built-in) AttributeError exception
You can catch your own exceptions in a try/except (Separately from others):
import my_exceptions
def raise_my_exception1():
raise my_exceptions.MyExceptions.MyValueError
def raise_other_exception():
raise Exception("Unexpected exception")
for func in [raise_my_exception1, raise_other_exception]:
try:
func()
except my_exceptions.MyExceptions.MyValueError as e:
print(e)
print("Handled exception. Do nothing!")
except Exception as e:
print(e)
print("Not handled exception. Raise it!")
raise e
Output:
>>> python2 test.py
This is my MyValueError. Inherited from 'ValueError'
Handled exception. Do nothing!
Unexpected exception
Not handled exception. Raise it!
Traceback (most recent call last):
File "test.py", line 20, in <module>
raise e
Exception: Unexpected exception
And of course, you have many choice to use this own exception collector.
You can create an instance from the exception collector class:
import my_exceptions
exception_collector = my_exceptions.MyExceptions()
def raise_my_exception1():
raise exception_collector.MyValueError
If you are a strict OOP
developer, your can inherited your "functional" class from your exception class. In that case your can use the exceptions as "instance exceptions" (with self
). Probably this way what you are looking for!
Example:
import my_exceptions
class FunctionalClass(my_exceptions.MyExceptions):
def raise_my_exception1(self):
raise self.MyValueError
def raise_other_exception(self):
raise Exception("Unexpected exception")
functional_instance = FunctionalClass()
for func in [functional_instance.raise_my_exception1, functional_instance.raise_other_exception]:
try:
func()
except my_exceptions.MyExceptions.MyValueError as e:
print(e)
print("Handled exception. Do nothing!")
except Exception as e:
print(e)
print("Not handled exception. Raise it!")
raise e
Output:
>>> python2 test.py
This is my MyValueError. Inherited from 'ValueError'
Handled exception. Do nothing!
Unexpected exception
Not handled exception. Raise it!
Traceback (most recent call last):
File "test.py", line 23, in <module>
raise e
Exception: Unexpected exception
Upvotes: 1