Say I have the following four variables:
>>> f1 = (print, 1, 2 ,3 ,4)
>>> f2 = (exit, 1, 2 ,3 ,4)
>>> f3 = (1, 2, 3, 4)
>>> f4 = 4
In a hypothetical program, I expect each of those variables to hold a tuple, whose first item should be the name of a function, and whose subsequent items should be said function's parameters, in order.
I could call a function stored in this way like so:
>>> f1[0](*f1[1:])
1 2 3 4
However, most of these variables are not in the excepted format, and I would like to be able to encapsulate the calling of them inside try
/except
blocks in order to handle those situations.
Now, even though the function calls of f2
, f3
and f4
break for radically different reason, they all throw the same kind of exception, a TypeError
:
>>> f2[0](*f2[1:])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __call__() takes from 1 to 2 positional arguments but 5 were given
>>> f3[0](*f3[1:])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> f4[0](*f4[1:])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not subscriptable
So that doing a generic:
try:
f[0](*f[1:])
except TypeError:
# handle exception
Would not provide me with enough information to handle each exception accordingly.
What would be the correct way to differentiate between distinct exceptions of the same type in Python?
So, you need to use a different method of calling than function(*tuple)
. Here is an example of a function fun_apply
that calls a particular function with positional and keyword arguments. It adds an explicit check to make sure that args
is iterable and kwargs
inherits from collection.Mapping
.
from collections import Mapping
def fun_apply(f, args=None, kwargs=None):
if args is None:
args = []
if kwargs is None:
kwargs = {}
try:
args = iter(args)
except TypeError:
# handle args being non-iterable
pass
if isinstance(kwargs, collections.Mapping):
pass
else:
# handle kwargs being a non-mapping
pass
if hasattr(f, '__call__'):
pass
else:
# handle f being non-callable
pass
try:
f(*args, **kwargs)
except TypeError as e:
raise TypeError(e)
The other option is to process the message
string explicitly, but this could have unintended consequences and the error messages themselves might differ between versions of Python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With