![](https://secure.gravatar.com/avatar/5615a372d9866f203a22b2c437527bbb.jpg?s=120&d=mm&r=g)
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@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