![](https://secure.gravatar.com/avatar/f3ba3ecffd20251d73749afbfa636786.jpg?s=120&d=mm&r=g)
On 17 July 2017 at 04:59, Ken Kundert <python-ideas@shalmirane.com> wrote:
Nick, I see. The Python C interface provides a very simple way of raising an exception in the case where the exception is only passed one argument, the error message. It even makes it easy to interpolate arguments into that error message. If it is important to include other arguments, as with OSError, one would presumably use another mechanism that requires more effort.
Your suggestion of providing an alternative to PyErr_Format() that squirreled away its arguments into the exception and deferred their interpolation into the error message seems like a very nice approach. But as you say, it does not seem trivial to implement in C. If it could be extended to support named arguments, it does have the benefit that it could unify the way exceptions are raise from C.
I'll note that while it wouldn't be trivial, it *should* at least theoretically be possible to share the string segmentation and processing steps with the f-string implementation. However, I also realised that a much simpler approach to the same idea would instead look like: PyErr_SetFromAttributes(PyExc_NameError, "name '%.200s' is not defined", "name", name); Where the field names alternate with the field values in the argument list, rather than being embedded in the format string. Ignoring error handling, the implementation would then be something like: - split va_list into a list of field names and a list of field values - set the exception via `PyErr_SetObject(exc_type, PyUnicode_Format(exc_msg, field_values))` - retrieve the just set exception and do `PyObject_SetAttr(exc, field_name, field_value)` for each field with a non-NULL name
The alternative would be to simply enhance the individual exceptions on an as needed basis as you suggested earlier. That could be easy if the exceptions are only raised in one or two places. Do you have a sense for how many places raise some of these common exceptions such as NameError, KeyError, etc.?
A quick check shows around a dozen hits for PyExc_NameError in c files (all in ceval.c), and most of the hits for NameError in Python files being related to catching it rather than raising it. PyExc_KeyError is mentioned in a dozen or so C files (most of them raising it, a few of them check for it being raised elsewhere), and while the hits in Python files still mostly favour catching it, it's raised explicitly in the standard library more often than NameError is. The nice thing about the PyErr_SetFromAttributes approach at the C API level is that it pairs nicely with the following approach at the constructor level: class NameError(Exception): def __init__(self, message, *, name=None): super().__init__(message) self.name = name Something like KeyError may want to distinguish between "key value was None" and "key value wasn't reported when raising the exception" (by not defining the attribute at all in the latter case), but PyErr_SetFromAttributes wouldn't need to care about those kinds of details. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia