FAQ
Hello

I've found out about a fundamental problem of attribute lookup, the
hard way.

asyncore.py uses the following code:

class dispatcher:
# ...
def __getattr__(self, attr):
return getattr(self.socket, attr)

Now suppose that I'm asking for some attribute not provided by
dispatcher: The lookup mechanism will apparently try to find it
directly and fail, generating an AttributeError; next it will call
__getattr__ to find the attribute. So far, no problems.

But I used a property much like this:
import asyncore
class Peer(asyncore.dispatcher):
... def _get_foo(self):
... # caused by a bug, several stack levels deeper
... raise AttributeError('hidden!')
... foo = property(_get_foo)
...

and as the error message suggests, the original AttributeError is
hidden by the lookup mechanism:
Peer().foo
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/lib/python2.4/asyncore.py", line 366, in __getattr__
return getattr(self.socket, attr)
AttributeError: 'NoneType' object has no attribute 'foo'

Is there anything that can be done about this? If there are no better
solutions, perhaps the documentation for property() could point out
this pitfall?

- Thomas

--
If you want to reply by mail, substitute my first and last name for
'foo' and 'bar', respectively, and remove '.invalid'.

Search Discussions

  • Aahz at Dec 29, 2004 at 4:06 am
    In article <87hdm5hnet.fsf at thomas.local>,
    Thomas Rast wrote:
    I've found out about a fundamental problem of attribute lookup, the
    hard way. Maybe.
    asyncore.py uses the following code:

    class dispatcher:
    # ...
    def __getattr__(self, attr):
    return getattr(self.socket, attr)

    Now suppose that I'm asking for some attribute not provided by
    dispatcher: The lookup mechanism will apparently try to find it
    directly and fail, generating an AttributeError; next it will call
    __getattr__ to find the attribute. So far, no problems.

    But I used a property much like this:
    import asyncore
    class Peer(asyncore.dispatcher):
    ... def _get_foo(self):
    ... # caused by a bug, several stack levels deeper
    ... raise AttributeError('hidden!')
    ... foo = property(_get_foo)
    ...
    You're not supposed to use properties with classic classes.
    --
    Aahz (aahz at pythoncraft.com) <*> http://www.pythoncraft.com/

    "19. A language that doesn't affect the way you think about programming,
    is not worth knowing." --Alan Perlis
  • David M. Cooke at Dec 29, 2004 at 5:07 am

    aahz at pythoncraft.com (Aahz) writes:

    In article <87hdm5hnet.fsf at thomas.local>,
    Thomas Rast wrote:
    class dispatcher:
    # ...
    def __getattr__(self, attr):
    return getattr(self.socket, attr)
    import asyncore
    class Peer(asyncore.dispatcher):
    ... def _get_foo(self):
    ... # caused by a bug, several stack levels deeper
    ... raise AttributeError('hidden!')
    ... foo = property(_get_foo)
    ...
    You're not supposed to use properties with classic classes.
    Even if dispatcher was a new-style class, you still get the same
    behaviour (or misbehaviour) -- Peer().foo still raises AttributeError
    with the wrong message.

    A simple workaround is to put a try ... except AttributeError block in
    his _get_foo(), which would re-raise with a different error that
    wouldn't be caught by getattr. You could even write a property
    replacement for that:
    class HiddenAttributeError(Exception):
    ... pass
    def robustprop(fget):
    ... def wrapped_fget(self):
    ... try:
    ... return fget(self)
    ... except AttributeError, e:
    ... raise HiddenAttributeError(*e.args)
    ... return property(fget=wrapped_fget)

    Ideally, I think the better way is if getattr, when raising
    AttributeError, somehow reused the old traceback (which would point
    out the original problem). I don't know how to do that, though.

    --
    \/|<
    /--------------------------------------------------------------------------\
    David M. Cooke
    cookedm(at)physics(dot)mcmaster(dot)ca
  • Nicolas Fleury at Dec 29, 2004 at 11:55 pm

    David M. Cooke wrote:
    Ideally, I think the better way is if getattr, when raising
    AttributeError, somehow reused the old traceback (which would point
    out the original problem). I don't know how to do that, though.
    Maybe a solution could be to put the attribute name in the
    AttributeError exception object, and use it in getattr; if the name
    doesn't match, the exception is re-raised. It's still not flawless, but
    would reduce risk of errors.

    Nicolas
  • Kamilche at Dec 31, 2004 at 1:26 am

    Thomas Rast wrote:
    I've found out about a fundamental problem of attribute lookup, the
    hard way... Is there anything that can be done about this?
    It seems to me that the main problem is you're raising an AttributeError
    when an attribute is private. AttributeError is only raised when an
    attribute is not found. If you found it, but it's private, that's a
    different problem. Try raising a custom exception instead of an
    AttributeError, if you can.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedDec 29, '04 at 2:02a
activeDec 31, '04 at 1:26a
posts5
users5
websitepython.org

People

Translate

site design / logo © 2022 Grokbase