Hi jmward01,
I'm not really sure what you mean by "boilerplate heavy objects".
*Boilerplate* generally applies to the amount of source code you have to
write. I don't think that a two line class (perhaps a couple of extra
lines if you give it a docstring) justifies the name "boilerplate":
class MySpecialException(Exception):
pass
In my experience, that covers the majority of custom exceptions I've
needed. (More on this below.)
As for "heavy objects", it's true that classes are moderately
heavyweight:
py> sys.getsizeof(Exception)
400
but the instances are relatively lightweight:
py> sys.getsizeof(Exception('spam eggs'))
96
and if you're stressed out by that, you might be using the wrong
language :-)
So I'm not quite sure what specific part of this you are worried about:
memory consumption or lines of code.
More below.
On Mon, Oct 12, 2020 at 09:16:37PM -0000, [email protected] wrote:
> I generally find exception objects are really just boilerplate heavy
> objects masking what I really want them to be, function calls:
>
> class MySpecialException(Exception):
> def __init__(self, some, variables, i, am, tracking):
> self.some = some
> ...
To me, that looks like something of a code smell.
https://en.wikipedia.org/wiki/Code_smell
I am suspicious of exceptions that have lots of values thrown into them.
With very few exceptions (pun intended :-) the model of exceptions I
expect to see is like the bulk of built-in exceptions. They typically
apply to a single value, for a single reason.
py> ord(1)
--> TypeError: ord() expected string of length 1, but int found
So consider that, maybe, your exceptions are doing too much.
In your code snippet, the try...except block seems to be literally
useless. You are literally raising an exception, only to immediately
catch it again, then do a test, and depending on that True/False result
of that test, either suppress the exception or re-raise it.
> ...
> try:
> if some_test_that_fails(variables):
> raise MySpecialException(a, b, c, d, e, f)
> except MySpecialException as e:
> logger.warning(f"BAD THING {e.a} HAPPENED!")
> if not handle_it(e.a, e.b, e.c, e.f):
> raise
> ...
I think this is more naturally written without the redundant raise
followed by catch:
if some_test_that_fails(variables):
# presumably "variables" include a, b, c, d, e, f
logger.warning(f"BAD THING {a} HAPPENED!")
if not handle_it(a, b, c, d, e, f):
raise MySpecialException(a, b, c, d, e, f)
But even better would be for `handle_it` to be more discriminating.
Rather than have it return a flag:
True <-- success
False <-- "an error occurred"
which you handle by raising a catch-all exception that lists no fewer
than six things that may have caused the error (a through f), I think
that a better design would be for handle_it to directly raise a more
specific exception:
if some_test_that_fails(variables):
# presumably "variables" include a, b, c, d, e, f
logger.warning(f"BAD THING {a} HAPPENED!")
handle_it(a, b, c, d, e, f)
Exceptions raised by `handle_it` probably need only refer to one
specific value, not a through f, with a specific exception cause, such
as TypeError, ValueError, etc.
> Instead of needing a whole new class definition, wouldn't it be nice to just
> have something like:
>
> ....
> #notice there isn't a boilerplate custom class created!
> try:
> if some_test_that_fails(variables):
> #I still have a base exception to fall back on for handlers that don't
> know my special exception
> raise Exception.my_special_exception(a, b, c, d, e, f)
How does Exception have a `my_special_exception` method? What does it
return? It has to return either an exception class or an exception
instance, but which class?
How does it know that the arguments a, b, .... f (which are anonymous
expressions) should be bound to names "a", "b", "c" etc?
What if I don't want names "a", etc but something more meaningful? If I
call:
raise Exception.apeiron_error(None, x or y, obj.widget.status())
what happens? How does Exception know about my apeiron_error method, and
what does it do with the arguments passed?
> except Exception.my_special_excpetion(a:int, b:str, d, e, f):
How does this know to catch only the exception raised by the
`my_special_exception` method?
My guess is that you are proposing that some form of structural pattern
matching, but precisely what form?
> The core idea here is that we are just passing control, so why make
> exceptions an exception to how control is normally passed, via
> functions. Just a thought.
Or you could just not use exceptions at all, and just call the function
you want to handle the error.
--
Steve
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/S2N7CF5I3XSQ3TWVOMY42TUWBA6KDPTF/
Code of Conduct: http://python.org/psf/codeofconduct/