Metaclass for inheriting comparison functions#
This module defines a metaclass InheritComparisonMetaclass
to
inherit comparison functions in Cython extension types. In Python 2,
the special methods __richcmp__
, __cmp__
and __hash__
are
only inherited as a whole: defining just 1 or 2 of these will prevent
the others from being inherited.
To solve this issue, you can use InheritComparisonMetaclass
as a Cython “metaclass” (see sage.cpython.cython_metaclass
for the
general mechanism). If you do this for an extension type which defines
neither __richcmp__
nor __cmp__
, then both these methods are
inherited from the base class (the MRO is not used).
In Sage, this is in particular used for
sage.structure.element.Element
to support comparisons using
the coercion framework.
None of this is relevant to Python classes, which inherit comparison methods anyway.
AUTHOR:
Jeroen Demeyer (2015-05-22): initial version, see Issue #18329
- class sage.misc.inherit_comparison.InheritComparisonClasscallMetaclass[source]#
Bases:
ClasscallMetaclass
,InheritComparisonMetaclass
Combine
ClasscallMetaclass
withInheritComparisonMetaclass
.
- class sage.misc.inherit_comparison.InheritComparisonMetaclass[source]#
Bases:
type
If the type does not define
__richcmp__
nor__cmp__
, inherit both these methods from the base class. The difference with plain extension types is that comparison is inherited even if__hash__
is defined.EXAMPLES:
sage: # needs sage.misc.cython sage: cython( ....: ''' ....: cimport cython ....: ....: from sage.misc.inherit_comparison cimport InheritComparisonMetaclass ....: ....: cdef class Base(): ....: def __richcmp__(left, right, int op): ....: print("Calling Base.__richcmp__") ....: return left is right ....: ....: cdef class Derived(Base): ....: def __hash__(self): ....: return 1 ....: ....: cdef class DerivedWithRichcmp(Base): ....: @cython.always_allow_keywords(False) ....: def __getmetaclass__(_): ....: from sage.misc.inherit_comparison import InheritComparisonMetaclass ....: return InheritComparisonMetaclass ....: def __hash__(self): ....: return 1 ....: ''') sage: a = Derived() sage: a == a True sage: b = DerivedWithRichcmp() sage: b == b Calling Base.__richcmp__ True
>>> from sage.all import * >>> # needs sage.misc.cython >>> cython( ... ''' ... cimport cython ....: >>> from sage.misc.inherit_comparison cimport InheritComparisonMetaclass ....: >>> cdef class Base(): ... def __richcmp__(left, right, int op): ... print("Calling Base.__richcmp__") ... return left is right ....: >>> cdef class Derived(Base): ... def __hash__(self): ... return Integer(1) ....: >>> cdef class DerivedWithRichcmp(Base): ... @cython.always_allow_keywords(False) ... def __getmetaclass__(_): ... from sage.misc.inherit_comparison import InheritComparisonMetaclass ... return InheritComparisonMetaclass ... def __hash__(self): ... return Integer(1) ... ''') >>> a = Derived() >>> a == a True >>> b = DerivedWithRichcmp() >>> b == b Calling Base.__richcmp__ True