[Python-ideas] Arguments to exceptions
Steven D'Aprano
steve at pearwood.info
Thu Jul 6 14:56:32 EDT 2017
On Thu, Jul 06, 2017 at 01:59:02PM -0400, Mark E. Haase wrote:
> On Thu, Jul 6, 2017 at 5:58 AM, Paul Moore <p.f.moore at gmail.com> wrote:
>
> > To use the (already
> > over-used) NameError example, Ken's proposal doesn't include any
> > change to how NameError exceptions are raised to store the name
> > separately on the exception.
> >
>
> Maybe I'm misunderstanding you, but the proposal has a clear example of
> raising NameError and getting the name attribute from the exception
> instance:
>
> try:
> raise NameError(name=name, template="name '{name}' is not defined.")
> except NameError as e:
> name = e.kwargs['name']
> msg = str(e)
> ...
What prevents the programmer from writing this?
raise NameError(nym=s, template="name '{nym}' is not defined.")
Or any other keyword name for that matter. Since the exception class
accepts arbitrary keyword arguments, we have to expect that it could be
used with arbitrary keyword arguments.
Only the exception subclass knows how many and what information it
expects:
- NameError knows that it expects a name;
- IndexError knows that it expects an index;
- OSError knows that it expects anything up to five arguments
(errno, errstr, winerr, filename1, filename2);
etc. BaseException cannot be expected to enforce that. Ken's suggestion
to put the argument handling logic in BaseException doesn't give us any
way to guarantee that NameError.kwargs['name'] will even exist, or that
NameError.args[0] is the name.
> > Yes. Because he tries to extract the name component of a NameError,
> > and yet that component isn't stored anywhere - under his proposal or
> > under current CPython.
> >
>
> I'm not sure what you mean by "extract", but the proposal calls for the
> name to be passed as a keyword argument (see above) and stored in
> self.kwargs:
>
>
> class BaseException:
> def __init__(self, *args, **kwargs):
> self.args = args
> self.kwargs = kwargs
Keyword *or positional argument*.
Even if given as a keyword argument, it could use any keyword. That's a
problem. Assuming it will be "name" is fragile and barely any better
than the status quo, and it's harder to use than named attributes.
If there is a need for NameError to make the name programmably
discoverable without scraping the error message, then as PEP 352
recommends, it should be made available via an attribute: err.name, not
err.args[0] or err.kwargs['name'].
Here's a proof of concept of the sort of thing we could do that is
backwards compatible and follows PEP 352:
class NameError(Exception):
def __init__(self, *args):
self.args = args
if len(args) == 2:
self.name = args[0]
else:
self.name = None
def __str__(self):
if len(self.args) == 1:
return str(self.args[0])
elif len(self.args) == 2:
return "[{}] {}".format(*self.args)
elif self.args:
return str(self.args)
return ''
--
Steven
More information about the Python-ideas
mailing list