diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index 7c2d753f4c3111..cffc08f59b99d2 100644 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -333,7 +333,7 @@ def loadfile(self, filename): modname = 'turtledemo.' + filename __import__(modname) self.module = sys.modules[modname] - with open(self.module.__file__, 'r') as f: + with open(self.module.__file__, encoding='utf-8') as f: chars = f.read() self.text.delete("1.0", "end") self.text.insert("1.0", chars) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst new file mode 100644 index 00000000000000..c2212267ce6fa4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst @@ -0,0 +1,2 @@ +Speed up calls to :func:`hasattr` and three-argument :func:`getattr` for +unassigned attributes in an object's :attr:`~object.__slots__` by roughly 6x. diff --git a/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst b/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst new file mode 100644 index 00000000000000..95f8e2fb7f4f8b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst @@ -0,0 +1,2 @@ +The :mod:`turtledemo` viewer now reads each demo script as UTF-8 instead of +the locale encoding. diff --git a/Objects/object.c b/Objects/object.c index 971ac1b7a68669..c7aeba0cee22c6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1924,6 +1924,19 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, if (descr != NULL) { f = Py_TYPE(descr)->tp_descr_get; if (f != NULL && PyDescr_IsData(descr)) { + // gh-157840: We special-case member descriptors here to avoid + // allocating an extra AttributeError + if (suppress && Py_IS_TYPE(descr, &PyMemberDescr_Type)) { + PyMemberDef *member = ((PyMemberDescrObject *)descr)->d_member; + if (member->type == Py_T_OBJECT_EX + && !(member->flags & Py_AUDIT_READ) + && PyObject_TypeCheck(obj, PyDescr_TYPE(descr))) { + PyObject **addr = _PyMember_GetOffset(obj, member); + if (FT_ATOMIC_LOAD_PTR(*addr) == NULL) { + goto done; + } + } + } res = f(descr, obj, (PyObject *)Py_TYPE(obj)); if (res == NULL && suppress && PyErr_ExceptionMatches(PyExc_AttributeError)) {