Abstract methods¶
- class sage.misc.abstract_method.AbstractMethod(f, optional=False)[source]¶
- Bases: - object- Constructor for abstract methods. - EXAMPLES: - sage: def f(x): ....: "doc of f" ....: return 1 sage: x = abstract_method(f); x <abstract method f at ...> sage: x.__doc__ 'doc of f' sage: x.__name__ 'f' sage: x.__module__ '__main__' - >>> from sage.all import * >>> def f(x): ... "doc of f" ... return Integer(1) >>> x = abstract_method(f); x <abstract method f at ...> >>> x.__doc__ 'doc of f' >>> x.__name__ 'f' >>> x.__module__ '__main__' - is_optional()[source]¶
- Return whether an abstract method is optional or not. - EXAMPLES: - sage: class AbstractClass: ....: @abstract_method ....: def required(): pass ....: ....: @abstract_method(optional = True) ....: def optional(): pass sage: AbstractClass.required.is_optional() False sage: AbstractClass.optional.is_optional() True - >>> from sage.all import * >>> class AbstractClass: ... @abstract_method ... def required(): pass ....: >>> @abstract_method(optional = True) ... def optional(): pass >>> AbstractClass.required.is_optional() False >>> AbstractClass.optional.is_optional() True 
 
- sage.misc.abstract_method.abstract_method(f=None, optional=False)[source]¶
- Abstract methods. - INPUT: - f– a function
- optional– boolean (default:- False)
 - The decorator - abstract_methodcan be used to declare methods that should be implemented by all concrete derived classes. This declaration should typically include documentation for the specification for this method.- The purpose is to enforce a consistent and visual syntax for such declarations. It is used by the Sage categories for automated tests (see - Sets.Parent.test_not_implemented).- EXAMPLES: - We create a class with an abstract method: - sage: class A(): ....: ....: @abstract_method ....: def my_method(self): ....: ''' ....: The method :meth:`my_method` computes my_method ....: ....: EXAMPLES:: ....: ....: ''' ....: pass sage: A.my_method <abstract method my_method at ...> - >>> from sage.all import * >>> class A(): ....: >>> @abstract_method ... def my_method(self): ... ''' ... The method :meth:`my_method` computes my_method ....: >>> EXAMPLES:: ....: >>> ''' ... pass >>> A.my_method <abstract method my_method at ...> - The current policy is that a - NotImplementedErroris raised when accessing the method through an instance, even before the method is called:- sage: x = A() sage: x.my_method Traceback (most recent call last): ... NotImplementedError: <abstract method my_method at ...> - >>> from sage.all import * >>> x = A() >>> x.my_method Traceback (most recent call last): ... NotImplementedError: <abstract method my_method at ...> - It is also possible to mark abstract methods as optional: - sage: class A(): ....: ....: @abstract_method(optional = True) ....: def my_method(self): ....: ''' ....: The method :meth:`my_method` computes my_method ....: ....: EXAMPLES:: ....: ....: ''' ....: pass sage: A.my_method <optional abstract method my_method at ...> sage: x = A() sage: x.my_method NotImplemented - >>> from sage.all import * >>> class A(): ....: >>> @abstract_method(optional = True) ... def my_method(self): ... ''' ... The method :meth:`my_method` computes my_method ....: >>> EXAMPLES:: ....: >>> ''' ... pass >>> A.my_method <optional abstract method my_method at ...> >>> x = A() >>> x.my_method NotImplemented - The official mantra for testing whether an optional abstract method is implemented is: - sage: if x.my_method is not NotImplemented: ....: x.my_method() ....: else: ....: print("x.my_method is not available.") x.my_method is not available. - >>> from sage.all import * >>> if x.my_method is not NotImplemented: ... x.my_method() ... else: ... print("x.my_method is not available.") x.my_method is not available. - Discussion - The policy details are not yet fixed. The purpose of this first implementation is to let developers experiment with it and give feedback on what’s most practical. - The advantage of the current policy is that attempts at using a non implemented methods are caught as early as possible. On the other hand, one cannot use introspection directly to fetch the documentation: - sage: x.my_method? # todo: not implemented - >>> from sage.all import * >>> x.my_method? # todo: not implemented - Instead one needs to do: - sage: A._my_method? # todo: not implemented - >>> from sage.all import * >>> A._my_method? # todo: not implemented - This could probably be fixed in - sage.misc.sageinspect.- Todo - what should be the recommended mantra for existence testing from the class? - Todo - should extra information appear in the output? The name of the class? That of the super class where the abstract method is defined? - Todo - look for similar decorators on the web, and merge - Implementation details - Technically, an abstract_method is a non-data descriptor (see Invoking Descriptors in the Python reference manual). - The syntax - @abstract_methodw.r.t. @abstract_method(optional = True) is achieved by a little trick which we test here:- sage: abstract_method(optional = True) <function abstract_method.<locals>.<lambda> at ...> sage: abstract_method(optional = True)(version) <optional abstract method version at ...> sage: abstract_method(version, optional = True) <optional abstract method version at ...> - >>> from sage.all import * >>> abstract_method(optional = True) <function abstract_method.<locals>.<lambda> at ...> >>> abstract_method(optional = True)(version) <optional abstract method version at ...> >>> abstract_method(version, optional = True) <optional abstract method version at ...> 
- sage.misc.abstract_method.abstract_methods_of_class(cls)[source]¶
- Return the required and optional abstract methods of the class. - EXAMPLES: - sage: class AbstractClass: ....: @abstract_method ....: def required1(): pass ....: ....: @abstract_method(optional = True) ....: def optional2(): pass ....: ....: @abstract_method(optional = True) ....: def optional1(): pass ....: ....: @abstract_method ....: def required2(): pass sage: sage.misc.abstract_method.abstract_methods_of_class(AbstractClass) {'optional': ['optional1', 'optional2'], 'required': ['required1', 'required2']} - >>> from sage.all import * >>> class AbstractClass: ... @abstract_method ... def required1(): pass ....: >>> @abstract_method(optional = True) ... def optional2(): pass ....: >>> @abstract_method(optional = True) ... def optional1(): pass ....: >>> @abstract_method ... def required2(): pass >>> sage.misc.abstract_method.abstract_methods_of_class(AbstractClass) {'optional': ['optional1', 'optional2'], 'required': ['required1', 'required2']}