[ZODB-Dev] "getattr" can hide "ConflictError"

Tim Peters tim at zope.com
Sun Oct 5 20:36:40 EDT 2003


[Dieter Maurer]
> When Python's "getattr" is called with a default argument
> ("getattr(obj,name,default)") it will return the default
> whenever "PyObject_getAttr(obj,name)" raises an exception.
>
> This also happens, when the exception is a "ReadConflictError"
> or "SystemExit" or another exception not directly related to
> attribute lookup.

Note that this depends on the version of Python in use.  From the NEWS file
for Python 2.2b1:

  - getattr(obj, name, default) now only catches AttributeError, as
    documented, rather than returning the default value for all
    exceptions (which could mask bugs in a __getattr__ hook, for
    example).

For example, here in 2.3.2:

>>> class C:
        def __getattr__(self, name):
            raise ValueError

>>> c = C()
>>> getattr(c, 'whatever', None)

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in -toplevel-
    getattr(c, 'whatever', None)
  File "<pyshell#3>", line 3, in __getattr__
    raise ValueError
ValueError
>>>

Despite that the 2.1 docs didn't match the behavior of the 2.1
implementation, the chance that somebody's code relied on the actual 2.1
behavior made it impossible to change this in a 2.1 bugfix release.  So
fixing this breakage had to wait until 2.2.

Note, however, that hasattr() continues to suppress all exceptions:

>>> hasattr(c, 'whatever')
False
>>>

For that reason, and especially in Zope and ZODB (where getting an attribute
can have enormously complex side effects -- much more so than I think Guido
ever anticipated), checking for attribute existence via

    if getattr(obj, attr, impossible_value) is not impossible_value:

can be preferable to using

    if hasattr(obj, attr):

in Python 2.2 or later.




More information about the ZODB-Dev mailing list