Skip to content

Commit b6e8304

Browse files
GH-95822: Need _PyType_Lookup() in descriptor howto code equivalent. (GH-95967) (#96100)
1 parent eb182fe commit b6e8304

File tree

1 file changed

+21
-1
lines changed

1 file changed

+21
-1
lines changed

Doc/howto/descriptor.rst

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,11 +582,18 @@ a pure Python equivalent:
582582

583583
.. testcode::
584584

585+
def find_name_in_mro(cls, name, default):
586+
"Emulate _PyType_Lookup() in Objects/typeobject.c"
587+
for base in cls.__mro__:
588+
if name in vars(base):
589+
return vars(base)[name]
590+
return default
591+
585592
def object_getattribute(obj, name):
586593
"Emulate PyObject_GenericGetAttr() in Objects/object.c"
587594
null = object()
588595
objtype = type(obj)
589-
cls_var = getattr(objtype, name, null)
596+
cls_var = find_name_in_mro(objtype, name, null)
590597
descr_get = getattr(type(cls_var), '__get__', null)
591598
if descr_get is not null:
592599
if (hasattr(type(cls_var), '__set__')
@@ -663,6 +670,15 @@ a pure Python equivalent:
663670
def __getattr__(self, name):
664671
return ('getattr_hook', self, name)
665672

673+
class D1:
674+
def __get__(self, obj, objtype=None):
675+
return type(self), obj, objtype
676+
677+
class U1:
678+
x = D1()
679+
680+
class U2(U1):
681+
pass
666682

667683
.. doctest::
668684
:hide:
@@ -696,6 +712,10 @@ a pure Python equivalent:
696712
>>> b.g == b['g'] == ('getattr_hook', b, 'g')
697713
True
698714

715+
>>> u2 = U2()
716+
>>> object_getattribute(u2, 'x') == u2.x == (D1, u2, U2)
717+
True
718+
699719
Note, there is no :meth:`__getattr__` hook in the :meth:`__getattribute__`
700720
code. That is why calling :meth:`__getattribute__` directly or with
701721
``super().__getattribute__`` will bypass :meth:`__getattr__` entirely.

0 commit comments

Comments
 (0)