Skip to content

Conversation

@methane
Copy link
Member

@methane methane commented Jan 13, 2018

Skip raising AttributeError when tp_getattro == PyObject_GenericGetAttr

https://bugs.python.org/issue32544

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea!

(Sorry I am a bit slow with ABCMeta, because I moved to another country.)

Include/object.h Outdated
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *);
/* Same to PyObject_GetAttr(), but don't raise AttributeError. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should read "Same as ..."

dict as the last parameter. */
PyAPI_FUNC(PyObject *)
_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *);
_PyObject_GenericGetAttrWithDict(PyObject *, PyObject *, PyObject *, int);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this change be backward incompatible? Or is this function is not covered by the backwards compatibility guarantees?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK, APIs starting with underscore are private.
Third party libs shouldn't expect backward compatibility.
I don't know should I add Include/internal/object.h or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see. But I don't know about Include/internal/object.h either. Probably @serhiy-storchaka can advise on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the signature of _PyObject_GenericGetAttrWithDict() LGTM. As for Include/internal/object.h, left this to other issue.

ret = (*tp->tp_getattro)(v, name);
}
}
else if (tp->tp_getattr != NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there is some code duplication with PyObject_GetAttr, does it make sense to factor it out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@methane Yes this idea looks good.

@ilevkivskyi
Copy link
Member

Also I think we need a NEWS item for this.

Objects/object.c Outdated
}
if (tp->tp_getattro != NULL) {
if (tp->tp_getattro == PyObject_GenericGetAttr) {
ret = _PyObject_GenericGetAttrWithDict(v, name, NULL, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _PyObject_GenericGetAttrWithDict() raise an AttributeError? If can't, it is better to just return the result here. PyErr_ExceptionMatches(PyExc_AttributeError) has a non-zero cost, in some cases it can be significant. For example see bpo-31336.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it may call descriptor. Any exception can be raised.
suppress=1 only suppress AttributeError raised from _PyObject_GenericGetAttrWithDict
directly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed _PyObject_GenericGetAttrWithDict() to suppress AttributeError
from descriptors too.
Since _PyObject_GenericGetAttrWithDict is performance critical function,
I'll run benchmark suite before merge this.

@serhiy-storchaka serhiy-storchaka added the performance Performance or resource usage label Jan 15, 2018
@@ -0,0 +1,3 @@
``hasattr(obj, name)`` and ``getattr(obj, name, default)`` is about 4 times
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a native speaker, but I would use "are" here instead of "is".

@methane methane merged commit 378edee into python:master Jan 16, 2018
@methane methane deleted the fast-hasattr branch January 16, 2018 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance or resource usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants