getattr() woes

T

Thomas Rast

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:
.... 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:
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
 
A

Aahz

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:

... 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.
 
D

David M. Cooke

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:
.... 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.
 
N

Nicolas Fleury

David said:
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
 
K

Kamilche

Thomas said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top