Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Fast methods via Cython
This module provides extension classes with useful methods of cython speed, that python classes can inherit.
.. NOTE::
This module provides a cython base class :class:`WithEqualityById` implementing unique instance behaviour, and a cython base class :class:`FastHashable_class`, which has a quite fast hash whose value can be freely chosen at initialisation time.
AUTHOR:
- Simon King (2013-02): Original version - Simon King (2013-10): Add :class:`Singleton`
"""
#***************************************************************************** # Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
from __future__ import absolute_import, print_function
from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.constant_function import ConstantFunction
from cpython.object cimport Py_EQ, Py_NE
cdef class WithEqualityById: """ Provide hash and equality test based on identity.
.. NOTE::
This class provides the unique representation behaviour of :class:`~sage.structure.unique_representation.UniqueRepresentation`, together with :class:`~sage.structure.unique_representation.CachedRepresentation`.
EXAMPLES:
Any instance of :class:`~sage.structure.unique_representation.UniqueRepresentation` inherits from :class:`WithEqualityById`. ::
sage: class MyParent(Parent): ....: def __init__(self, x): ....: self.x = x ....: def __hash__(self): ....: return hash(self.x) sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById) True
Inheriting from :class:`WithEqualityById` provides unique representation behaviour::
sage: a = MyUniqueParent(1) sage: b = MyUniqueParent(2) sage: c = MyUniqueParent(1) sage: a is c True sage: d = MyUniqueParent(-1) sage: a == d False
The hash inherited from ``MyParent`` is replaced by a hash that coincides with :class:`object`'s hash::
sage: hash(a) == hash(a.x) False sage: hash(a) == object.__hash__(a) True
.. WARNING::
It is possible to inherit from :class:`~sage.structure.unique_representation.UniqueRepresentation` and then overload equality test in a way that destroys the unique representation property. We strongly recommend against it! You should use :class:`~sage.structure.unique_representation.CachedRepresentation` instead.
::
sage: class MyNonUniqueParent(MyUniqueParent): ....: def __eq__(self, other): ....: return self.x^2 == other.x^2 sage: a = MyNonUniqueParent(1) sage: d = MyNonUniqueParent(-1) sage: a is MyNonUniqueParent(1) True sage: a == d True sage: a is d False
""" def __hash__(self): """ The hash provided by this class coincides with that of ``<type 'object'>``.
TESTS::
sage: class MyParent(Parent): ....: def __init__(self, x): ....: self.x = x ....: def __hash__(self): ....: return hash(self.x) sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById) True sage: a = MyUniqueParent(1) sage: hash(a) == hash(a.x) False sage: hash(a) == object.__hash__(a) True
sage: from sage.misc.fast_methods import WithEqualityById sage: o1 = WithEqualityById() sage: o2 = WithEqualityById() sage: hash(o1) == hash(o2) False """ # This is the default hash function in Python's object.c:
def __richcmp__(self, other, int op): """ Equality test provided by this class is by identity.
TESTS::
sage: class MyParent(Parent): ....: def __init__(self, x): ....: self.x = x ....: def __hash__(self): ....: return hash(self.x) sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById) True sage: a = MyUniqueParent(1) sage: b = MyUniqueParent(-1)
Equality test takes into account identity::
sage: a == b False
When comparing with an object which is not an instance of ``WithEqualityById``, the other object determines the comparison::
sage: class AlwaysEqual: ....: def __eq__(self, other): ....: return True sage: AlwaysEqual() == a True sage: a == AlwaysEqual() True
Check that :trac:`19628` is fixed::
sage: from sage.misc.lazy_import import LazyImport sage: lazyQQ = LazyImport('sage.all', 'QQ') sage: PolynomialRing(lazyQQ, 'ijk') is PolynomialRing(QQ, 'ijk') True sage: PolynomialRing(QQ, 'ijkl') is PolynomialRing(lazyQQ, 'ijkl') True """ # This only makes sense if "other" is also of type WithEqualityById
cdef class FastHashable_class: """ A class that has a fast hash method, returning a pre-assigned value.
.. NOTE::
This is for internal use only. The class has a cdef attribute ``_hash``, that needs to be assigned (for example, by calling the init method, or by a direct assignement using cython). This is slower than using :func:`provide_hash_by_id`, but has the advantage that the hash can be prescribed, by assigning a cdef attribute ``_hash``.
TESTS::
sage: from sage.misc.fast_methods import FastHashable_class sage: H = FastHashable_class(123) sage: hash(H) 123 """ def __init__(self, h): """ TESTS::
sage: from sage.misc.fast_methods import FastHashable_class sage: H = FastHashable_class(123) sage: hash(H) # indirect doctest 123 """
def __hash__(self): """ TESTS::
sage: from sage.misc.fast_methods import FastHashable_class sage: H = FastHashable_class(123) sage: hash(H) # indirect doctest 123
"""
class Singleton(WithEqualityById, metaclass=ClasscallMetaclass): """ A base class for singletons.
A singleton is a class that allows to create not more than a single instance. This instance can also belong to a subclass, but it is not possible to have several subclasses of a singleton all having distinct unique instances.
In order to create a singleton, just add :class:`Singleton` to the list of base classes::
sage: from sage.misc.fast_methods import Singleton sage: class C(Singleton, SageObject): ....: def __init__(self): ....: print("creating singleton") sage: c = C() creating singleton sage: c2 = C() sage: c is c2 True
The unique instance of a singleton stays in memory as long as the singleton itself does.
Pickling, copying, hashing, and comparison are provided for by :class:`Singleton` according to the singleton paradigm. Note that pickling fails if the class is replaced by a sub-sub-class after creation of the instance::
sage: class D(C): ....: pass sage: import __main__ # This is only needed ... sage: __main__.C = C # ... in doctests sage: __main__.D = D # same here, only in doctests sage: orig = type(c) sage: c.__class__ = D sage: orig == type(c) False sage: loads(dumps(c)) Traceback (most recent call last): ... AssertionError: <class '__main__.D'> is not a direct subclass of <class 'sage.misc.fast_methods.Singleton'> """ @staticmethod def __classcall__(cls): """ Create an instance ``O`` of the given class ``cls``, and make it so that in future both ``cls.__call__`` and ``O.__class__.__call__`` are constant functions returning ``O``.
EXAMPLES::
sage: from sage.misc.fast_methods import Singleton sage: class C(Singleton, Parent): ....: def __init__(self): ....: print("creating singleton") ....: Parent.__init__(self, base=ZZ, category=Rings()) sage: c = C() creating singleton sage: import __main__ # This is only needed ... sage: __main__.C = C # ... in doctests sage: loads(dumps(c)) is copy(c) is C() # indirect doctest True """
def __copy__(self): """ There is a unique instance of a singleton, hence, copying returns ``self``.
EXAMPLES::
sage: from sage.misc.fast_methods import Singleton sage: class C(Singleton, Parent): ....: def __init__(self): ....: print("creating singleton") ....: Parent.__init__(self, base=ZZ, category=Rings()) sage: c = C() creating singleton sage: import __main__ # This is only needed ... sage: __main__.C = C # ... in doctests sage: loads(dumps(c)) is copy(c) is C() # indirect doctest True """
def __reduce__(self): """ There is a unique instance of a singleton, hence, pickling returns ``self``.
EXAMPLES::
sage: from sage.misc.fast_methods import Singleton sage: class C(Singleton, Parent): ....: def __init__(self): ....: print("creating singleton") ....: Parent.__init__(self, base=ZZ, category=Rings()) ....: sage: c = C() creating singleton sage: import __main__ # This is only needed ... sage: __main__.C = C # ... in doctests sage: loads(dumps(c)) is copy(c) is C() # indirect doctest True
The pickle data mainly consist of the class of the unique instance, which may be a subclass of the original class used to create the instance.If the class is replaced by a sub-sub-class after creation of the instance, pickling fails. See the doctest in :class:`Singleton`. """ |