[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