@@ -147,7 +147,7 @@ that has generally a slower attribute access, but fully supports
147147cached methods. We remark, however, that cached methods are
148148* much* faster if attribute access works. So, we expect that
149149:class:`~sage. structure. element. ElementWithCachedMethod` will
150- hardly by used.
150+ hardly be used.
151151::
152152
153153 sage: # needs sage. misc. cython
@@ -1882,7 +1882,7 @@ cdef class CachedMethodCaller(CachedFunction):
18821882 sage: a.f(5) is a.f(y=1,x=5)
18831883 True
18841884
1885- The method can be called as a bound function using the same cache::
1885+ The method can be called as a unbound function using the same cache::
18861886
18871887 sage: a.f(5) is Foo.f(a, 5)
18881888 True
@@ -1940,7 +1940,7 @@ cdef class CachedMethodCaller(CachedFunction):
19401940 True
19411941 """
19421942 if self ._instance is None :
1943- # cached method bound to a class
1943+ # cached method bound to a class i.e. unbound method, such as ``Foo.f``
19441944 instance = args[0 ]
19451945 args = args[1 :]
19461946 return self ._cachedmethod.__get__ (instance)(* args, ** kwds)
@@ -1987,7 +1987,7 @@ cdef class CachedMethodCaller(CachedFunction):
19871987 5
19881988 """
19891989 if self ._instance is None :
1990- # cached method bound to a class
1990+ # cached method bound to a class i.e. unbound method, such as ``CachedMethodTest.f``
19911991 instance = args[0 ]
19921992 args = args[1 :]
19931993 return self ._cachedmethod.__get__ (instance).cached(* args, ** kwds)
@@ -2548,16 +2548,15 @@ cdef class CachedMethod():
25482548 sage: a.f(3) is res
25492549 True
25502550
2551- Note, however, that the :class:`CachedMethod` is replaced by a
2552- :class:`CachedMethodCaller` or :class:`CachedMethodCallerNoArgs`
2553- as soon as it is bound to an instance or class::
2551+ Note, however, that accessing the attribute directly will call :meth:`__get__`,
2552+ and returns a :class:`CachedMethodCaller` or :class:`CachedMethodCallerNoArgs`.
25542553
25552554 sage: P.<a,b,c,d> = QQ[]
25562555 sage: I = P*[a,b]
25572556 sage: type(I.__class__.gens)
25582557 <class 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
2559-
2560- So, you would hardly ever see an instance of this class alive.
2558+ sage: type(I.__class__.__dict__["gens"])
2559+ < class 'sage.misc.cachefunc.CachedMethod'>
25612560
25622561 The parameter ``key`` can be used to pass a function which creates a
25632562 custom cache key for inputs. In the following example, this parameter is
@@ -2640,13 +2639,17 @@ cdef class CachedMethod():
26402639 sage: a.f0()
26412640 4
26422641
2643- The computations in method ``f`` are tried to store in a
2644- dictionary assigned to the instance ``a``::
2642+ For methods with parameters, computations in method ``f`` are
2643+ tried to store in a dictionary assigned to the instance ``a``::
26452644
26462645 sage: hasattr(a, '_cache__f')
26472646 True
26482647 sage: a._cache__f
26492648 {((2,), ()): 4}
2649+ sage: a._cache_f0
2650+ Traceback (most recent call last):
2651+ ...
2652+ AttributeError: 'Foo' object has no attribute '_cache_f0'...
26502653
26512654 As a shortcut, useful to speed up internal computations,
26522655 the same dictionary is also available as an attribute
@@ -2694,6 +2697,8 @@ cdef class CachedMethod():
26942697 def __call__ (self , inst , *args , **kwds ):
26952698 """
26962699 Call the cached method as a function on an instance.
2700+ This code path is not used directly except in a few rare cases,
2701+ see examples for details.
26972702
26982703 INPUT:
26992704
@@ -2745,20 +2750,48 @@ cdef class CachedMethod():
27452750 ....: def f(self, n=2):
27462751 ....: return self._x^n
27472752 sage: a = Foo(2)
2753+
2754+ Initially ``_cache__f`` is not an attribute of ``a``::
2755+
2756+ sage: hasattr(a, "_cache__f")
2757+ False
2758+
2759+ When the attribute is accessed (thus ``__get__`` is called),
2760+ the cache is created and assigned to the attribute::
2761+
2762+ sage: a.f
2763+ Cached version of <function Foo.f at 0x...>
2764+ sage: a._cache__f
2765+ {}
27482766 sage: a.f()
27492767 4
2768+ sage: a.f.cache
2769+ {((2,), ()): 4}
2770+ sage: a._cache__f
2771+ {((2,), ()): 4}
27502772
2751- Note that we cannot provide a direct test, since ``a.f`` is
2752- an instance of :class:`CachedMethodCaller`. But during its
2753- initialisation, this method was called in order to provide the
2754- cached method caller with its cache, and, if possible, assign
2755- it to an attribute of ``a``. So, the following is an indirect
2756- doctest::
2773+ Testing the method directly::
27572774
2758- sage: a.f.cache # indirect doctest
2759- {((2,), ()): 4}
2775+ sage: a = Foo(2)
2776+ sage: hasattr(a, "_cache__f")
2777+ False
2778+ sage: Foo.__dict__["f"]._get_instance_cache(a)
2779+ {}
27602780 sage: a._cache__f
2781+ {}
2782+ sage: a.f()
2783+ 4
2784+ sage: Foo.__dict__["f"]._get_instance_cache(a)
27612785 {((2,), ()): 4}
2786+
2787+ Using ``__dict__`` is needed to access this function because
2788+ ``Foo.f`` would call ``__get__`` and thus create a
2789+ :class:`CachedMethodCaller`::
2790+
2791+ sage: type(Foo.f)
2792+ <class 'sage.misc.cachefunc.CachedMethodCaller'>
2793+ sage: type(Foo.__dict__["f"])
2794+ <class 'sage.misc.cachefunc.CachedMethod'>
27622795 """
27632796 default = {} if self ._cachedfunc.do_pickle else NonpicklingDict()
27642797 try :
@@ -2868,8 +2901,9 @@ cdef class CachedSpecialMethod(CachedMethod):
28682901
28692902 For new style classes ``C``, it is not possible to override a special
28702903 method, such as ``__hash__``, in the ``__dict__`` of an instance ``c`` of
2871- ``C``, because Python will for efficiency reasons always use what is
2872- provided by the class, not by the instance.
2904+ ``C``, because Python will always use what is provided by the class, not
2905+ by the instance to avoid metaclass confusion. See
2906+ `<https://docs.python.org/3/reference/datamodel.html#special-method-lookup>`_.
28732907
28742908 By consequence, if ``__hash__`` would be wrapped by using
28752909 :class:`CachedMethod`, then ``hash(c)`` will access ``C.__hash__`` and bind
0 commit comments