#12951: Support cached_methods on extension types
-------------------------------+--------------------------------------------
Reporter: SimonKing | Owner: jason
Type: enhancement | Status: needs_review
Priority: major | Milestone: sage-5.1
Component: misc | Resolution:
Keywords: | Work issues:
Report Upstream: N/A | Reviewers:
Authors: Simon King | Merged in:
Dependencies: | Stopgaps:
-------------------------------+--------------------------------------------
Changes (by {'newvalue': u'Simon King', 'oldvalue': ''}):
* status: new => needs_review
* author: => Simon King
Comment:
As it turns out, it is still impossible to use arbitrary decorators on
c(p)def functions or methods. However, the attached patch makes it
possible to use the decorator on def-methods of extension classes. That
used to fail, because of the attribute error mentioned in the ticket
description. It is of course still required that the instances of the
extension class either allow to override an attribute of the class by an
attribute of the instance, or that the instance has a public attribute
`__cached_methods`.
For the latter case, we now have (from the doc tests):
{{{
sage: cython_code = [
... "from sage.misc.cachefunc import cached_method",
... "cdef class MyClass:",
... " cdef public dict __cached_methods",
... " @cached_method",
... " def f(self, a,b):",
... " return a*b"]
sage: cython(os.linesep.join(cython_code))
sage: P = MyClass()
sage: P.f(2,3)
6
sage: P.f(2,3) is P.f(2,3)
True
}}}
Note that by #11115, sage.structure.parent.Parent has the
`__cached_methods` attribute. Hence, any cdef subclass of Parent will do!
Providing attribute access is a bit more tricky, since it is needed that
an attribute inherited by the instance from its class can be overridden on
the instance. That is why providing a `__getattr__` would not be enough in
the following example:
{{{
sage: cython_code = [
... "from sage.misc.cachefunc import cached_method",
... "cdef class MyOtherClass:",
... " cdef dict D",
... " def __init__(self):",
... " self.D = {}",
... " def __setattr__(self, n,v):",
... " self.D[n] = v",
... " def __getattribute__(self, n):",
... " try:",
... " return self.D[n]",
... " except KeyError:",
... " pass",
... " return getattr(type(self),n).__get__(self)",
... " @cached_method",
... " def f(self, a,b):",
... " return a+b"]
sage: cython(os.linesep.join(cython_code))
sage: Q = MyOtherClass()
sage: Q.f(2,3)
5
sage: Q.f(2,3) is Q.f(2,3)
True
}}}
Supporting attribute access apparently is more complicated than the other
approach, and probably not recommended. However, on cached methods, it is
somehow faster than the easier method:
{{{
sage: timeit("a = P.f(2,3)") # random
625 loops, best of 3: 1.3 µs per loop
sage: timeit("a = Q.f(2,3)") # random
625 loops, best of 3: 931 ns per loop
}}}
Needs review!
--
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/12951#comment:1>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica,
and MATLAB
--
You received this message because you are subscribed to the Google Groups
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sage-trac?hl=en.