-
-
Notifications
You must be signed in to change notification settings - Fork 674
Cached methods with do_pickle=True for UniqueRepresentation #40874
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
8b663ed
c00afe8
c017291
3db1fcc
b0261ca
c9a9b59
45e7b83
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,6 @@ | |
r""" | ||
Cached Functions and Methods | ||
|
||
AUTHORS: | ||
|
||
- William Stein: initial version, (inspired by conversation with Justin Walker) | ||
- Mike Hansen: added doctests and made it work with class methods. | ||
- Willem Jan Palenstijn: add CachedMethodCaller for binding cached methods to | ||
instances. | ||
- Tom Boothby: added DiskCachedFunction. | ||
- Simon King: improved performance, more doctests, cython version, | ||
CachedMethodCallerNoArgs, weak cached function, cached special methods. | ||
- Julian Rueth (2014-03-19, 2014-05-09, 2014-05-12): added ``key`` parameter, allow caching | ||
for unhashable elements, added ``do_pickle`` parameter | ||
|
||
EXAMPLES: | ||
|
||
By :issue:`11115`, cached functions and methods are now also | ||
|
@@ -430,8 +418,19 @@ Note that shallow copy of mutable objects may behave unexpectedly:: | |
2 | ||
sage: b.f is a.f | ||
False | ||
""" | ||
|
||
AUTHORS: | ||
|
||
- William Stein: initial version, (inspired by conversation with Justin Walker) | ||
- Mike Hansen: added doctests and made it work with class methods. | ||
- Willem Jan Palenstijn: add CachedMethodCaller for binding cached methods to | ||
instances. | ||
- Tom Boothby: added DiskCachedFunction. | ||
- Simon King: improved performance, more doctests, cython version, | ||
CachedMethodCallerNoArgs, weak cached function, cached special methods. | ||
- Julian Rueth (2014-03-19, 2014-05-09, 2014-05-12): added ``key`` parameter, allow caching | ||
for unhashable elements, added ``do_pickle`` parameter | ||
""" | ||
# **************************************************************************** | ||
# Copyright (C) 2008 William Stein <[email protected]> | ||
# Mike Hansen <[email protected]> | ||
|
@@ -864,6 +863,27 @@ cdef class CachedFunction(): | |
""" | ||
return _cached_function_unpickle, (self.__cached_module__, self.__name__, self.cache) | ||
|
||
def is_pickled_with_cache(self): | ||
""" | ||
Return ``True`` if this cached function is pickled with the cache. | ||
|
||
EXAMPLES:: | ||
|
||
sage: @cached_function | ||
....: def f(x): | ||
....: return x | ||
....: | ||
sage: f.is_pickled_with_cache() | ||
False | ||
sage: @cached_function(do_pickle=True) | ||
....: def f(x): | ||
....: return x | ||
....: | ||
sage: f.is_pickled_with_cache() | ||
True | ||
""" | ||
return self.do_pickle | ||
|
||
######### | ||
# Introspection | ||
# | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,6 @@ | |
r""" | ||
Factory for cached representations | ||
|
||
.. SEEALSO:: | ||
|
||
:mod:`sage.structure.unique_representation` | ||
|
||
Using a :class:`UniqueFactory` is one way of implementing a *cached | ||
representation behaviour*. In spite of its name, using a | ||
:class:`UniqueFactory` is not enough to ensure the *unique representation | ||
|
@@ -36,13 +32,16 @@ sophisticated, then generally | |
:class:`~sage.structure.unique_representation.CachedRepresentation` is much | ||
easier to use than a factory. | ||
|
||
.. SEEALSO:: | ||
|
||
:mod:`sage.structure.unique_representation` | ||
|
||
AUTHORS: | ||
|
||
- Robert Bradshaw (2008): initial version. | ||
- Simon King (2013): extended documentation. | ||
- Robert Bradshaw (2008): initial version | ||
- Simon King (2013): extended documentation | ||
- Julian Rueth (2014-05-09): use ``_cache_key`` if parameters are unhashable | ||
""" | ||
|
||
#***************************************************************************** | ||
# Copyright (C) 2008 Robert Bradshaw <[email protected]> | ||
# 2014 Julian Rueth <[email protected]> | ||
|
@@ -423,13 +422,11 @@ cdef class UniqueFactory(SageObject): | |
self._cache[version, _cache_key(key)] = obj | ||
obj._factory_data = self, version, key, extra_args | ||
|
||
# Install a custom __reduce__ method on the instance "obj" | ||
# that we just created. We only do this if the class of | ||
# "obj" has a generic __reduce__ method, which is either | ||
# object.__reduce__ or __reduce_cython__, the | ||
# auto-generated pickling function for Cython. | ||
# Install a custom __reduce_ex__ method (that overrides __reduce__ | ||
# method) on the instance obj that we just created. We only do this | ||
# if the class of obj has a generic object.__reduce__ method. | ||
f = obj.__class__.__reduce__ | ||
if f.__objclass__ is object or f.__name__ == "__reduce_cython__": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this change? |
||
if f.__objclass__ is object: | ||
obj.__reduce_ex__ = types.MethodType(generic_factory_reduce, obj) | ||
except AttributeError: | ||
pass | ||
|
@@ -734,6 +731,10 @@ def generic_factory_reduce(self, proto): | |
""" | ||
Used to provide a ``__reduce__`` method if one does not already exist. | ||
|
||
INPUT: | ||
|
||
- ``proto`` -- positive integer; protocol number | ||
|
||
EXAMPLES:: | ||
|
||
sage: V = QQ^6 # needs sage.modules | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,7 @@ | |
r""" | ||
Unique Representation | ||
|
||
Abstract classes for cached and unique representation behavior. | ||
|
||
.. SEEALSO:: | ||
|
||
:class:`sage.structure.factory.UniqueFactory` | ||
|
||
AUTHORS: | ||
|
||
- Nicolas M. Thiery (2008): Original version. | ||
- Simon A. King (2013-02): Separate cached and unique representation. | ||
- Simon A. King (2013-08): Extended documentation. | ||
|
||
This modules defines abstract classes for cached and unique representation behavior. | ||
|
||
What is a cached representation? | ||
================================ | ||
|
@@ -537,6 +526,16 @@ class that inherits from :class:`UniqueRepresentation`: By adding | |
unique representation behaviour, one has to implement hash and equality test | ||
accordingly, for example by inheriting from | ||
:class:`~sage.misc.fast_methods.WithEqualityById`. | ||
|
||
.. SEEALSO:: | ||
|
||
:class:`sage.structure.factory.UniqueFactory` | ||
|
||
AUTHORS: | ||
|
||
- Nicolas M. Thiery (2008): initial version | ||
- Simon A. King (2013-02): separated cached and unique representation | ||
- Simon A. King (2013-08): extended documentation | ||
""" | ||
# **************************************************************************** | ||
# Copyright (C) 2008 Nicolas M. Thiery <nthiery at users.sf.net> | ||
|
@@ -598,6 +597,8 @@ def __classcall__(cls, *args, **options): | |
assert isinstance(instance, cls) | ||
if instance.__class__.__reduce__ == WithPicklingByInitArgs.__reduce__: | ||
instance._reduction = (cls, args, options) | ||
instance.__class__.__getstate__ = WithPicklingByInitArgs.__getstate__ | ||
instance.__class__.__setstate__ = WithPicklingByInitArgs.__setstate__ | ||
return instance | ||
|
||
def __reduce__(self): | ||
|
@@ -613,9 +614,9 @@ def __reduce__(self): | |
|
||
sage: x = UniqueRepresentation() | ||
sage: x.__reduce__() # indirect doctest | ||
(<function unreduce at ...>, (<class 'sage.structure.unique_representation.UniqueRepresentation'>, (), {})) | ||
(<function unreduce at ...>, (<class 'sage.structure.unique_representation.UniqueRepresentation'>, (), {}), {}) | ||
""" | ||
return (unreduce, self._reduction) | ||
return (unreduce, self._reduction, self.__getstate__()) | ||
|
||
def __copy__(self): | ||
""" | ||
|
@@ -646,6 +647,78 @@ def __deepcopy__(self, memo): | |
""" | ||
return self | ||
|
||
def __getstate__(self): | ||
""" | ||
Used for pickling. | ||
|
||
An object of :class:`WithPicklingByInitArgs` does not keep its dictionary | ||
when pickled, because the object is constructed anew upon unpickling. | ||
|
||
Here we make some exceptions so that cached functions with | ||
``do_pickle=True`` attached to an object are kept in the pickle. | ||
|
||
EXAMPLES:: | ||
|
||
sage: from sage.structure.unique_representation import WithPicklingByInitArgs | ||
sage: class X(WithPicklingByInitArgs): | ||
....: def __init__(self, x): | ||
....: self._x = x | ||
....: @cached_method(do_pickle=True) | ||
....: def genus(self): | ||
....: return len(self._x) | ||
....: | ||
sage: import __main__; __main__.X = X # not needed in an interactive session | ||
sage: a = X((1,2,3)) | ||
sage: a.genus() | ||
3 | ||
sage: a.genus.cache | ||
3 | ||
sage: s = dumps(a) | ||
sage: a.genus.clear_cache() | ||
sage: a.genus.cache | ||
sage: b = loads(s) | ||
sage: b.genus.cache | ||
3 | ||
""" | ||
from sage.misc.cachefunc import CachedFunction | ||
d = {} | ||
try: | ||
for key, value in self.__dict__.items(): | ||
if isinstance(value, CachedFunction) and value.is_pickled_with_cache(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up question: What happens with static methods? Are they pickled? I don't think they should be but we should check if they are. |
||
d[key] = value | ||
except AttributeError: | ||
pass | ||
|
||
return d | ||
|
||
def __setstate__(self, d): | ||
""" | ||
Used for unpickling. | ||
|
||
EXAMPLES:: | ||
|
||
sage: from sage.structure.unique_representation import WithPicklingByInitArgs | ||
sage: class X(WithPicklingByInitArgs): | ||
....: def __init__(self, x): | ||
....: self._x = x | ||
....: @cached_method(do_pickle=False) | ||
....: def genus(self): | ||
....: return len(self._x) | ||
....: | ||
sage: import __main__; __main__.X = X # not needed in an interactive session | ||
sage: a = X((1,2,3)) | ||
sage: a.genus() | ||
3 | ||
sage: a.genus.cache | ||
3 | ||
sage: s = dumps(a) | ||
sage: a.genus.clear_cache() | ||
sage: a.genus.cache | ||
sage: b = loads(s) | ||
sage: b.genus.cache | ||
""" | ||
self.__dict__.update(d) | ||
|
||
|
||
def unreduce(cls, args, keywords): | ||
""" | ||
|
@@ -952,7 +1025,7 @@ class CachedRepresentation(WithPicklingByInitArgs): | |
|
||
sage: x = MyClass(value = 1) | ||
sage: x.__reduce__() | ||
(<function unreduce at ...>, (<class '__main__.MyClass'>, (), {'value': 1})) | ||
(<function unreduce at ...>, (<class '__main__.MyClass'>, (), {'value': 1}), {}) | ||
sage: x is loads(dumps(x)) | ||
True | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?