[Python-ideas] AtributeError inside __get__

Chris Angelico rosuav at gmail.com
Sun Dec 25 16:59:51 EST 2016


On Mon, Dec 26, 2016 at 8:03 AM, Nick Timkovich <prometheus235 at gmail.com> wrote:
> Are you saying that hasattr returning False was hiding a bug or is a bug?
> The former could be annoying to track down, though hasattr(X, 'y') == True.
> For the latter, having hasattr return False if an AttributeError is raised
> would allow the property decorator to retain identical functionality if it
> is used to replace a (sometimes) existing attribute.

This was touched on during the StopIteration discussions, but left
aside (it's not really connected, other than that exceptions are used
as a signal).

It's more that a property function raising AttributeError makes it
look like it doesn't exist.

Worth noting, though: The confusion only really comes up with hasattr.
If you simply try to access the property, you get an exception that
identifies the exact fault:

>>> X().y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in y
AttributeError: 'X' object has no attribute 'nonexisting'

Interestingly, the exception doesn't seem to have very useful arguments:

>>> ee.args
("'X' object has no attribute 'nonexisting'",)

So here's a two-part proposal that would solve Zaheri's problem:

1) Enhance AttributeError to include arguments for the parts in
quotes, for i18n independence.
2) Provide, in the docs, a hasattr replacement that checks the exception's args.

The new hasattr would look like this:

def hasattr(obj, name):
    try:
        getattr(obj, name)
        return True
    except AttributeError as e:
        if e.args[1] == obj.__class__.__name__ and e.args[2] == name:
            return False
        raise

Since it's just a recipe in the docs, you could also have a version
that works on current Pythons, but it'd need to do string manipulation
to compare - something like:

def hasattr(obj, name):
    try:
        getattr(obj, name)
        return True
    except AttributeError as e:
        if e.args[0] == "%r object has no attribute %r" % (
                obj.__class__.__name__, name):
            return False
        raise

I can't guarantee that this doesn't get some edge cases wrong, eg if
you have weird characters in your name. But it'll deal with the normal
cases, and it doesn't need any language changes - just paste that at
the top of your file.

Zaheri, would this solve your problem?

ChrisA


More information about the Python-ideas mailing list