[Tutor] exceptional behaviour

Remco Gerlich scarblac@pino.selwerd.nl
Thu, 24 Jan 2002 10:02:14 +0100


On  0, paul <polb@cableinet.co.uk> wrote:
> Here's the code for the catcher:

(snip code)

Ok, confirmed. String exceptions with a space don't work, at least not with
these strings, haven't tested much more.

> removing the space from the raise string allows it to work just fine, 
> it's not a problem, but it's hard to see why it should differentiate 
> between strings with spaces and those without.

Surprisingly, the final answer is that "problem2" is a valid name for a
Python identifier, but "problem 2" is not.

Let's quote a bit from the Language Reference,
http://www.python.org/doc/current/ref/exceptions.html , verse 5:

   "Exceptions are handled by string objects or class instances. Selection
   of a matching except clause is based on object identity (i.e., two
   different string objects with the same value represent different
   exceptions!)"

Now usually, if you have two string literals in different parts of your
program, they will *not* be the same object. So by default, this kind of
raise/except would not work at all. However. Since strings are immutable,
Python is allowed to intern() them, put all strings with a certain value in
the same memory, so that they *are* the same object.

It does the optimization with certain strings only, ones that are likely to
occur often - prime example: identifiers, or rather strings that could be
identifiers. You can not rely on this, the Python implementation is free to
change the choice of strings it interns from version to version.

So basically the anomaly isn't that "problem 2" doesn't work, but rather
that "problem2" does, because it looks like an identifier, is therefore
interned, and therefore it's the same object both times you use it.

Try typing e.g.

id("a test")
id("a test")
id("a test")
id("atest")
id("atest")
id("atest")

"a test" will give three different numbers, "atest" three times the same.

I agree that all of this is *very* counter intuitive, but string exceptions
are basically deprecated anyway.

Solutions:

- Define your errors at the top of the file, like 
  Problem_2_exception = "problem 2"
  and use 'raise Problem_2_exception' and 'except Problem_2_exception'

- Use class exceptions. You know you want to.

Avoiding spaces in exceptions is probably good enough, but *might* fail in
the future, if Python decides to stop interning strings that look like
identifiers, or when string exceptions are finally removed.

-- 
Remco Gerlich