[Python-ideas] Arguments to exceptions

Jeff Walker jeff.walker00 at yandex.com
Thu Jul 6 23:54:24 EDT 2017


Paul,
    I am having trouble understanding your response.

06.07.2017, 03:58, "Paul Moore" <p.f.moore at gmail.com>:
> On 6 July 2017 at 02:53, Jeff Walker <jeff.walker00 at yandex.com> wrote:
>>  Could you please expand on these statements:
>>
>>>   the idea doesn't actually solve the problem it is intended to
>>
>>  Specifically Ken started by saying that it should not be necessary to parse the
>>  messages to get the components of the message. He then gave an example
>>  where he was able to access the components of the message without parsing
>>  the message. So how is it that he is not solving the problem he intended to solve?
>
> Just to add my perspective here, his proposed solution (to modify
> BaseException) doesn't include any changes to the derived exceptions
> that would need to store the components. 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.
>
> So *as the proposal stands* it doesn't allow users to extract
> components of any exceptions, simply because the proposal doesn't
> suggest changing exceptions to *store* those components.
>
>>>   His solution can't work
>>
>>  Again, he gave an example where he was able to access the components of the
>>  message without parsing the message. Yet you claim his solution cannot work.
>>  Is his example wrong?
>
> 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.
>

Here is Ken's original proposal:

    class BaseException:
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

        def __str__(self):
            template = self.kwargs.get('template')
            if template is None:
                sep = self.kwargs.get('sep', ' ')
                return sep.join(str(a) for a in self.args)
            else:
                return template.format(*self.args, **self.kwargs)

The code for storing the arguments is in the constructor. You can access the
arguments through the args and kwargs attributes. This is exactly the way
BaseException works currently, except that it provides no support for kwargs.

Here is an example:

    class NameError(BaseException):
         pass

    try:
        raise NameError('welker', db='users', template='{0}: unknown {db}.')
    except NameError as e:
        unknown_name = e.args[0]
        missing_from = e.kwargs('db')
        print(str(e))

Given this example, please explain why it is you say that the arguments are not
be stored and are not accessible.

>>>   He hasn't demonstrated that there is a real problem
>>
>>  You yourself admitted that parsing a message to extract the components is
>>  undesirable. Ken and others, including myself, gave examples where this was
>>  necessary. Each example was given as either being a real problem or
>>  representative of a real problem. Are we all wrong?
>
> He's given examples of use cases. To that extent, Steven is being a
> touch absolute here. However, there has been some debate over whether
> those examples are valid. We've had multiple responses pointing out
> that the code examples aren't restricting what's in the try block
> sufficiently tightly, for example (the NameError case in particular
> was importing a file which, according to Ken himself, had potentially
> *thousands* of places where NameError could be raised). It's possible
> that introspecting exceptions is the right way to design a solution to
> this particular problem, but it does go against the normal design
> principles that have been discussed on this list and elsewhere many
> times. So, to demonstrate that there's a problem, it's necessary to
> address the question of whether the code could in fact have been
> written in a different manner that avoided the claimed problem.

People keep picking on that example, but Ken gave a reasonable justification
for why it was written that way. It was a script written for a knowledgeable user.
Further investment for a more 'correct' solution was neither desired nor justifiable.
By dismissing the example, you dismiss a use-model for Python that is one of
its strengths. It's ability to allow users to throw together powerful scripts with
minimal effort.

Also people seem to forget that he also pointed out that his proposal allows
error messages to be trivially translated to different languages:

     try:
        raise NameError('welker')
    except NameError as e:
        print('{}: nicht gefunden.'.format(e.args[0]))


More information about the Python-ideas mailing list