@@ -97,15 +97,6 @@ approach is still needed for cpdef methods::
9797 sage: O. direct_method( 5) is O. direct_method( 5)
9898 True
9999
100- In some cases, one would only want to keep the result in cache as long
101- as there is any other reference to the result. By :issue:`12215`, this is
102- enabled for :class:`~sage. structure. unique_representation. UniqueRepresentation`,
103- which is used to create unique parents: If an algebraic structure, such
104- as a finite field, is only temporarily used, then it will not stay in
105- cache forever. That behaviour is implemented using ``weak_cached_function``,
106- that behaves the same as ``cached_function``, except that it uses a
107- :class:`~sage. misc. weak_dict. CachedWeakValueDictionary` for storing the results.
108-
109100By :issue:`11115`, even if a parent does not allow attribute
110101assignment, it can inherit a cached method from the parent class of a
111102category ( previously, the cache would have been broken) ::
@@ -147,7 +138,7 @@ that has generally a slower attribute access, but fully supports
147138cached methods. We remark, however, that cached methods are
148139* much* faster if attribute access works. So, we expect that
149140:class:`~sage. structure. element. ElementWithCachedMethod` will
150- hardly by used.
141+ hardly be used.
151142::
152143
153144 sage: # needs sage. misc. cython
@@ -415,6 +406,30 @@ the parent as its first argument::
415406 sage: d = a. add_bigoh( 1) # needs sage. rings. padics
416407 sage: b. _cache_key( ) == d. _cache_key( ) # this would be True if the parents were not included
417408 False
409+
410+ Note that shallow copy of mutable objects may behave unexpectedly::
411+
412+ sage: class Foo:
413+ .... : @cached_method
414+ .... : def f( self) :
415+ .... : return self. x
416+ sage: from copy import copy, deepcopy
417+ sage: a = Foo( )
418+ sage: a. x = 1
419+ sage: a. f( )
420+ 1
421+ sage: b = copy( a)
422+ sage: b. x = 2
423+ sage: b. f( ) # incorrect!
424+ 1
425+ sage: b. f is a. f # this is the problem
426+ True
427+ sage: b = deepcopy( a)
428+ sage: b. x = 2
429+ sage: b. f( ) # correct
430+ 2
431+ sage: b. f is a. f
432+ False
418433"""
419434
420435# ****************************************************************************
@@ -1884,7 +1899,7 @@ cdef class CachedMethodCaller(CachedFunction):
18841899 sage: a.f(5) is a.f(y=1,x=5)
18851900 True
18861901
1887- The method can be called as a bound function using the same cache::
1902+ The method can be called as an unbound function using the same cache::
18881903
18891904 sage: a.f(5) is Foo.f(a, 5)
18901905 True
@@ -1942,7 +1957,7 @@ cdef class CachedMethodCaller(CachedFunction):
19421957 True
19431958 """
19441959 if self ._instance is None :
1945- # cached method bound to a class
1960+ # unbound cached method such as ``Foo.f``
19461961 instance = args[0 ]
19471962 args = args[1 :]
19481963 return self ._cachedmethod.__get__ (instance)(* args, ** kwds)
@@ -1989,7 +2004,7 @@ cdef class CachedMethodCaller(CachedFunction):
19892004 5
19902005 """
19912006 if self ._instance is None :
1992- # cached method bound to a class
2007+ # unbound cached method such as ``CachedMethodTest.f``
19932008 instance = args[0 ]
19942009 args = args[1 :]
19952010 return self ._cachedmethod.__get__ (instance).cached(* args, ** kwds)
@@ -2550,16 +2565,17 @@ cdef class CachedMethod():
25502565 sage: a.f(3) is res
25512566 True
25522567
2553- Note, however, that the :class:`CachedMethod` is replaced by a
2554- :class:`CachedMethodCaller` or :class:`CachedMethodCallerNoArgs`
2555- as soon as it is bound to an instance or class::
2568+ Note, however, that accessing the attribute directly will call :meth:`__get__`,
2569+ and returns a :class:`CachedMethodCaller` or :class:`CachedMethodCallerNoArgs`.
2570+
2571+ ::
25562572
25572573 sage: P.<a,b,c,d> = QQ[]
25582574 sage: I = P*[a,b]
25592575 sage: type(I.__class__.gens)
25602576 <class 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
2561-
2562- So, you would hardly ever see an instance of this class alive.
2577+ sage: type(I.__class__.__dict__["gens"])
2578+ < class 'sage.misc.cachefunc.CachedMethod'>
25632579
25642580 The parameter ``key`` can be used to pass a function which creates a
25652581 custom cache key for inputs. In the following example, this parameter is
@@ -2642,13 +2658,17 @@ cdef class CachedMethod():
26422658 sage: a.f0()
26432659 4
26442660
2645- The computations in method ``f`` are tried to store in a
2646- dictionary assigned to the instance ``a``::
2661+ For methods with parameters, the results of method ``f`` is attempted
2662+ to be stored in a dictionary attribute of the instance ``a``::
26472663
26482664 sage: hasattr(a, '_cache__f')
26492665 True
26502666 sage: a._cache__f
26512667 {((2,), ()): 4}
2668+ sage: a._cache_f0
2669+ Traceback (most recent call last):
2670+ ...
2671+ AttributeError: 'Foo' object has no attribute '_cache_f0'...
26522672
26532673 As a shortcut, useful to speed up internal computations,
26542674 the same dictionary is also available as an attribute
@@ -2696,6 +2716,8 @@ cdef class CachedMethod():
26962716 def __call__ (self , inst , *args , **kwds ):
26972717 """
26982718 Call the cached method as a function on an instance.
2719+ This code path is not used directly except in a few rare cases,
2720+ see examples for details.
26992721
27002722 INPUT:
27012723
@@ -2747,20 +2769,48 @@ cdef class CachedMethod():
27472769 ....: def f(self, n=2):
27482770 ....: return self._x^n
27492771 sage: a = Foo(2)
2772+
2773+ Initially ``_cache__f`` is not an attribute of ``a``::
2774+
2775+ sage: hasattr(a, "_cache__f")
2776+ False
2777+
2778+ When the attribute is accessed (thus ``__get__`` is called),
2779+ the cache is created and assigned to the attribute::
2780+
2781+ sage: a.f
2782+ Cached version of <function Foo.f at 0x...>
2783+ sage: a._cache__f
2784+ {}
27502785 sage: a.f()
27512786 4
2787+ sage: a.f.cache
2788+ {((2,), ()): 4}
2789+ sage: a._cache__f
2790+ {((2,), ()): 4}
27522791
2753- Note that we cannot provide a direct test, since ``a.f`` is
2754- an instance of :class:`CachedMethodCaller`. But during its
2755- initialisation, this method was called in order to provide the
2756- cached method caller with its cache, and, if possible, assign
2757- it to an attribute of ``a``. So, the following is an indirect
2758- doctest::
2792+ Testing the method directly::
27592793
2760- sage: a.f.cache # indirect doctest
2761- {((2,), ()): 4}
2794+ sage: a = Foo(2)
2795+ sage: hasattr(a, "_cache__f")
2796+ False
2797+ sage: Foo.__dict__["f"]._get_instance_cache(a)
2798+ {}
27622799 sage: a._cache__f
2800+ {}
2801+ sage: a.f()
2802+ 4
2803+ sage: Foo.__dict__["f"]._get_instance_cache(a)
27632804 {((2,), ()): 4}
2805+
2806+ Using ``__dict__`` is needed to access this function because
2807+ ``Foo.f`` would call ``__get__`` and thus create a
2808+ :class:`CachedMethodCaller`::
2809+
2810+ sage: type(Foo.f)
2811+ <class 'sage.misc.cachefunc.CachedMethodCaller'>
2812+ sage: type(Foo.__dict__["f"])
2813+ <class 'sage.misc.cachefunc.CachedMethod'>
27642814 """
27652815 default = {} if self ._cachedfunc.do_pickle else NonpicklingDict()
27662816 try :
@@ -2870,8 +2920,9 @@ cdef class CachedSpecialMethod(CachedMethod):
28702920
28712921 For new style classes ``C``, it is not possible to override a special
28722922 method, such as ``__hash__``, in the ``__dict__`` of an instance ``c`` of
2873- ``C``, because Python will for efficiency reasons always use what is
2874- provided by the class, not by the instance.
2923+ ``C``, because Python will always use what is provided by the class, not
2924+ by the instance to avoid metaclass confusion. See
2925+ `<https://docs.python.org/3/reference/datamodel.html#special-method-lookup>`_.
28752926
28762927 By consequence, if ``__hash__`` would be wrapped by using
28772928 :class:`CachedMethod`, then ``hash(c)`` will access ``C.__hash__`` and bind
0 commit comments