[Python-3000] exception-swallowing behaviour of hasattr

Dwayne C. Litzenberger dlitz at dlitz.net
Tue Jan 22 07:47:03 CET 2008


This issue has been raised before, but Guido thought that changing things 
in 2.x would break too much code.  See:

     http://mail.python.org/pipermail/python-dev/2005-February/051770.html
     http://mail.python.org/pipermail/python-dev/2005-December/058498.html
     http://bugs.python.org/issue504714

I'm bringing this up again because the arguments I've seen in favour of 
fixing hasattr have been fairly weak, and I'd like to raise some stronger 
ones.  Also, I haven't seen this issue considered specifically in the 
context of Python 3000.

The problem is that hasattr behaves just like the following code:

     def hasattr(obj, name):
         try:
             getattr(obj, name)
             return True
         except:
             return False

In Python 3000, all exceptions inherit from BaseException, so this is 
equivalent to:

     def hasattr(obj, name):
         try:
             getattr(obj, name)
             return True
         except BaseException:
             return False

There are three major things that are broken by this behaviour, which I 
don't think have been explicitly mentioned:

     1. If the Python interpreter receives SIGINT (usually triggered by 
        Ctrl-C) while executing obj.__getattr__ (or anything it calls), 
        hasattr silently returns False and the program continues running.

        Cause: KeyboardInterrupt is swallowed.

     2. If sys.exit is called within obj.__getattr__, hasattr silently 
        returns False and the program continues running.

        Cause: SystemExit is swallowed.

     3. If an assert statement fails within obj.__getattr__, hasattr 
        silently returns False and the program continues running.

        Cause: AssertionError is swallowed.

Also, because getattr(x,y,z) swallows only AttributeError, users naturally 
expect hasattr to behave the same way.  (This argument has been raised 
before.)

I propose a few alternate behaviours for hasattr (and their consequences):

     1. Swallow only AttributeError.

         - KeyboardInterrupt, SystemExit, and AssertionError are all passed 
           through, solving all three of the above problems.

         - The behaviour of hasattr is made consistent with getattr(x,y,z).

     2. Swallow only Exception.

         - KeyboardInterrupt and SystemExit are passed through, but 
           AssertionError is still swallowed.

         - Breaks less code than the previous option.

     3. Swallow Exception unless it's an AssertionError.

         - KeyboardInterrupt, SystemExit, and AssertionError are all passed 
           through, solving all three of the above problems.

         - Kind of ugly.

     4. Swallow everything except KeyboardInterrupt and SystemExit.

         - AssertionError is still swallowed, but the other problems are 
           fixed and this probably won't break any existing code.

I looked at bltinmodule.c, and any of these would be trivial to implement.

Ideally, I would like to see the first option implemented in Python 3000 
and one of the other options implemented in 2.x.

-- 
Dwayne C. Litzenberger <dlitz at dlitz.net>


More information about the Python-3000 mailing list