]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-95822: Need _PyType_Lookup() in descriptor howto code equivalent. (GH-95967)
authorRaymond Hettinger <rhettinger@users.noreply.github.com>
Fri, 19 Aug 2022 04:56:58 +0000 (23:56 -0500)
committerGitHub <noreply@github.com>
Fri, 19 Aug 2022 04:56:58 +0000 (23:56 -0500)
Doc/howto/descriptor.rst

index 5e9b110f0fe25445970157cdef8cdec22a707c73..91a6c31c33b8bde9e1f74d77ac3f17d555c14f3a 100644 (file)
@@ -582,11 +582,18 @@ a pure Python equivalent:
 
 .. testcode::
 
+    def find_name_in_mro(cls, name, default):
+        "Emulate _PyType_Lookup() in Objects/typeobject.c"
+        for base in cls.__mro__:
+            if name in vars(base):
+                return vars(base)[name]
+        return default
+
     def object_getattribute(obj, name):
         "Emulate PyObject_GenericGetAttr() in Objects/object.c"
         null = object()
         objtype = type(obj)
-        cls_var = getattr(objtype, name, null)
+        cls_var = find_name_in_mro(objtype, name, null)
         descr_get = getattr(type(cls_var), '__get__', null)
         if descr_get is not null:
             if (hasattr(type(cls_var), '__set__')
@@ -663,6 +670,15 @@ a pure Python equivalent:
         def __getattr__(self, name):
             return ('getattr_hook', self, name)
 
+    class D1:
+        def __get__(self, obj, objtype=None):
+            return type(self), obj, objtype
+
+    class U1:
+        x = D1()
+
+    class U2(U1):
+        pass
 
 .. doctest::
     :hide:
@@ -696,6 +712,10 @@ a pure Python equivalent:
     >>> b.g == b['g'] == ('getattr_hook', b, 'g')
     True
 
+    >>> u2 = U2()
+    >>> object_getattribute(u2, 'x') == u2.x == (D1, u2, U2)
+    True
+
 Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__`
 code.  That is why calling :meth:`__getattribute__` directly or with
 ``super().__getattribute__`` will bypass :meth:`__getattr__` entirely.