mirror of
https://github.com/python/cpython.git
synced 2025-11-08 21:52:45 +00:00
gh-106292: restore checking __dict__ in cached_property.__get__ (#106380)
* gh-106292: restore checking __dict__ in cached_property.__get__ Co-authored-by: Dong-hee Na <donghee.na92@gmail.com>
This commit is contained in:
parent
217f47d6e5
commit
838406b4fc
3 changed files with 36 additions and 10 deletions
|
|
@ -957,9 +957,10 @@ class singledispatchmethod:
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
### cached_property() - computed once per instance, cached as attribute
|
### cached_property() - property result cached as instance attribute
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
_NOT_FOUND = object()
|
||||||
|
|
||||||
class cached_property:
|
class cached_property:
|
||||||
def __init__(self, func):
|
def __init__(self, func):
|
||||||
|
|
@ -990,6 +991,8 @@ class cached_property:
|
||||||
f"instance to cache {self.attrname!r} property."
|
f"instance to cache {self.attrname!r} property."
|
||||||
)
|
)
|
||||||
raise TypeError(msg) from None
|
raise TypeError(msg) from None
|
||||||
|
val = cache.get(self.attrname, _NOT_FOUND)
|
||||||
|
if val is _NOT_FOUND:
|
||||||
val = self.func(instance)
|
val = self.func(instance)
|
||||||
try:
|
try:
|
||||||
cache[self.attrname] = val
|
cache[self.attrname] = val
|
||||||
|
|
|
||||||
|
|
@ -3037,6 +3037,25 @@ class TestCachedProperty(unittest.TestCase):
|
||||||
def test_doc(self):
|
def test_doc(self):
|
||||||
self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.")
|
self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.")
|
||||||
|
|
||||||
|
def test_subclass_with___set__(self):
|
||||||
|
"""Caching still works for a subclass defining __set__."""
|
||||||
|
class readonly_cached_property(py_functools.cached_property):
|
||||||
|
def __set__(self, obj, value):
|
||||||
|
raise AttributeError("read only property")
|
||||||
|
|
||||||
|
class Test:
|
||||||
|
def __init__(self, prop):
|
||||||
|
self._prop = prop
|
||||||
|
|
||||||
|
@readonly_cached_property
|
||||||
|
def prop(self):
|
||||||
|
return self._prop
|
||||||
|
|
||||||
|
t = Test(1)
|
||||||
|
self.assertEqual(t.prop, 1)
|
||||||
|
t._prop = 999
|
||||||
|
self.assertEqual(t.prop, 1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
Check for an instance-dict cached value in the :meth:`__get__` method of
|
||||||
|
:func:`functools.cached_property`. This better matches the pre-3.12 behavior
|
||||||
|
and improves compatibility for users subclassing
|
||||||
|
:func:`functools.cached_property` and adding a :meth:`__set__` method.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue