[Python-3000] exceptions with keyword arguments

Brett Cannon brett at python.org
Thu May 18 21:49:56 CEST 2006


On 5/18/06, tomer filiba <tomerfiliba at gmail.com> wrote:
>
> > Positional support is deprecated; there will only be support for a
> > single argument. Read
> > PEP 352 to see how BaseException will end up in Python 3000.
>
> i don't see how BaseException addresses issues like accessing
> attributes rather than positional args, or introducing something
> equivalent
> to ArgumentError. raising a TypeError is just semantically wrong in that
> case -- it has nothing to do with types whatsoever.



It doesn't address any of that.  It isn't meant to.  BaseException is the
base exception and is not meant to support the kitchen sink.


from the pep:
> > This PEP proposes introducing a new exception named BaseException
> > that is a new-style class and has a single attribute, message (that will
> > cause the deprecation of the existing args attribute)




well, how do you suggest passing back the error-code, or file name of
> exceptions like IOError, or the attribute name of an AttributeError?
> a single argument can only be used for pretty printing, not really
> providing
> information *about* the exception. so unless people would want to
> use regular expressions to *parse* the message, why not allow keyword
> arguments for extra info about the exception?



Subclassing.  You can override the constructor and do what you want.


> And I brought this up with Guido once and he was not enthusiastic
> > about it.  Basically, keep exceptions simple.  They are important
> > and basic enough to keep it simple.  If you want fancier support,
> > subclass Exception and add the support you want.




well, if guido pronounced on it than i guess it's settled, but why do you
> condsider *args to be simple and **kwargs not as simple? don't you
> think "ex.filename" is simpler/clearer than "ex[1]"?



I do.  I am in no way suggesting that positional arguments are better.  As I
said, positional arguments are not going to be supported in Python 3000.
The positional argument support is for backards-compatibility; that's why
BaseException will end up having the constructor defined as::

   def __init__(self, message=''):
        """Set the 'message' attribute'"""
        self.message = message


as specified in the PEP.  But that does not stop someone from overriding
BaseException in a subclass, as some built-ins do already.  So you can
easily add your filename attribute.::

  def __init__(self, filename):
      self.filename = filename
      BaseException.__init__(self, "%s does not exist" % filename)

This also allows you to come up with an informative message if you so desire
that is more standardized and based on some other argument.

-Brett

-tomer
>
> On 5/17/06, Brett Cannon <brett at python.org> wrote:
> >
> >
> >
> > On 5/17/06, tomer filiba <tomerfiliba at gmail.com> wrote:
> > > hi all
> > >
> > > i would like to suggest changing the base-exception class, whatever
> > > it may be (Exception/BaseException) to work with keyword arguments
> > > instead of positional ones.
> >
> >
> >
> > Positional support is deprecated; there will only be support for a
> single
> > argument.  Read PEP 352 to see how BaseException will end up in Python
> 3000.
> >
> > And I brought this up with Guido once and he was not enthusiastic about
> it.
> > Basically, keep exceptions simple.  They are important and basic enough
> to
> > keep it simple.  If you want fancier support, subclass Exception and add
> the
> > support you want.
> >
> > -Brett
> >
> > >
> > instead of
> >
> > try:
> >     ...
> > except IOError, ex:
> >     print ex[1]
> > # or
> > except IOError, (code, text, filename):
> >     ...
> >     # which means changes to code/text/filename do not change
> >     # the exception object
> >
> > use
> >
> > try:
> >     raise IOError(filename = "lala", code=17, text="blah blah blah")
> > except IOError, ex:
> >     ex.code = 18
> >     raise
> >
> > raise IndexError("invalid index", index = the_index)
> > raise KeyError("key not found", key = the_key)
> > raise AttributeError("attribute not found", name = name)
> >
> > where the new exception can be something like
> >
> > class Exception:
> >     def __init__(self, message = None, **kw):
> >         self._message = message
> >         self.__dict__.update(kw)
> >     def __repr__(self):
> >         attrs = sorted("%s = %r" % (k, v)
> >                        for k, v in self.__dict__.iteritems()
> >                        if not k.startswith("_"))
> >         return "<%s(%s, %s)>" % (self.__class__.__name__,
> >             self._message, ", ".join(attrs))
> >
> > class IOError(Exception):
> >    pass
> >
> > raise IOError(code = 17, text = "EBLAH", filename = "lalala")
> >
> > the builtin errors might want to enforce an "exception signature",
> >
> > class ExceptionSignature(Exception):
> >     attributes = []
> >     def __init__(self, *args, **kw):
> >          for name in self.attributes:
> >              assert name in kw, "expected an attribute named %s" %
> (name,)
> >          Exception.__init__(self, *args, **kw)
> >
> > class IOError(ExceptionSignature):
> >     attributes = ["code", "text", "filename"]
> >
> > or something like that, so the attributes of the exception are part
> > of its official interface.
> >
> > rationale:
> > * today, AttributeError's are raised as
> > AttributeError("%s object has no attribute %s" % ...)
> > which means analyzing the exception requires parsing text!
> >  * IOError (among others), for instance, does nasty and not-so-well
> > documented
> > overloading of named/positional arguments: when you pass 1-3 arguments,
> > they are stored in .args, but also in .errno, .strerror, and
> >  .filename. if you pass
> > more than 3 arguments, the attributes are all set to None and only
> > .args is filled.
> > yuck.
> >
> > you can see this for reference:
> > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496698
> >
> > ----
> >
> > that said, i would also want to introduce ArgumentError. there are
> > many times just a ValueError isn't enough. instead, having a builtin
> > ArgumentError would made things more clear:
> >
> > def write_to_file(the_file):
> >     if the_file.closed:
> >         raise ArgumentError("the file must be open", name = "the_file")
> >     the_file.write(...)
> >
> > and with ArgumentError included, calling functions with invalid
> > signatures would also raise ArgumentError. TypeError is quite
> > silly in this case, as it has nothing to do with the *type* of
> > the function or its arguments.
> >
> > >>> def f(a): pass
> > >>> f(1,2)
> > Traceback (most recent call last):
> >   File "<stdin>", line 1, in ?
> > *TypeError*: f() takes exactly 1 argument (2 given)
> > >>> type(f)
> > <type 'function'> # like any other function
> >
> > TypeError is too-broadly overloaded this way.
> >
> >
> > -tomer
> > _______________________________________________
> > Python-3000 mailing list
> >  Python-3000 at python.org
> > http://mail.python.org/mailman/listinfo/python-3000
> > Unsubscribe:
> > http://mail.python.org/mailman/options/python-3000/brett%40python.org
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/python-3000/attachments/20060518/b8f774a4/attachment.html 


More information about the Python-3000 mailing list