raise None
Terry Reedy
tjreedy at udel.edu
Wed Dec 30 23:00:16 EST 2015
On 12/30/2015 7:09 PM, Steven D'Aprano wrote:
> I have a lot of functions that perform the same argument checking each time:
>
> def spam(a, b):
> if condition(a) or condition(b): raise TypeError
> if other_condition(a) or something_else(b): raise ValueError
> if whatever(a): raise SomethingError
> ...
>
> def eggs(a, b):
> if condition(a) or condition(b): raise TypeError
> if other_condition(a) or something_else(b): raise ValueError
> if whatever(a): raise SomethingError
> ...
>
>
> Since the code is repeated, I naturally pull it out into a function:
>
> def _validate(a, b):
> if condition(a) or condition(b): raise TypeError
> if other_condition(a) or something_else(b): raise ValueError
> if whatever(a): raise SomethingError
>
> def spam(a, b):
> _validate(a, b)
> ...
>
> def eggs(a, b):
> _validate(a, b)
> ...
>
>
> But when the argument checking fails, the traceback shows the error
> occurring in _validate, not eggs or spam. (Naturally, since that is where
> the exception is raised.) That makes the traceback more confusing than it
> need be.
>
> So I can change the raise to return in the _validate function:
>
> def _validate(a, b):
> if condition(a) or condition(b): return TypeError
> if other_condition(a) or something_else(b): return ValueError
> if whatever(a): return SomethingError
>
>
> and then write spam and eggs like this:
>
> def spam(a, b):
> ex = _validate(a, b)
> if ex is not None: raise ex
> ...
>
>
> It's not much of a gain though. I save an irrelevant level in the traceback,
> but only at the cost of an extra line of code everywhere I call the
> argument checking function.
It is nicer than the similar standard idiom
try:
_validate(a, b)
except Exception as e:
raise e from None
If you could compute a reduced traceback, by copying one, then this
might work (based on Chris' idea.
def _validate(a, b):
ex = None
if condition(a) or condition(b): ex = TypeError
elif other_condition(a) or something_else(b): ex = ValueError
elif whatever(a): ex = SomethingError
if ex:
try: 1/0
except ZeroDivisionError as err: tb = err.__traceback__
tb = <copy of tb with this frame omitted>
raise ex.with_traceback(tb)
> But suppose we allowed "raise None" to do nothing. Then I could rename
> _validate to _if_error and write this:
>
> def spam(a, b):
> raise _if_error(a, b)
> ...
>
>
> and have the benefits of "Don't Repeat Yourself" without the unnecessary,
> and misleading, extra level in the traceback.
>
> Obviously this doesn't work now, since raise None is an error, but if it did
> work, what do you think?
Perhaps a bit too magical, but maybe not.
--
Terry Jan Reedy
More information about the Python-list
mailing list