Skip to content

Commit 3d79e3c

Browse files
committed
Fix some errors in documentation of cachefunc
1 parent 39ebbe4 commit 3d79e3c

File tree

1 file changed

+55
-21
lines changed

1 file changed

+55
-21
lines changed

src/sage/misc/cachefunc.pyx

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ that has generally a slower attribute access, but fully supports
147147
cached 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

Comments
 (0)