I implement abstract class with abc package. The program below shows no problems.
Is there any way to make it fail because abstract MyMethod
did have an argument a
but the implementation of 'MyMethod' in class Derivative
didn't? So I would like specify not only methods in the interface class Base
but also arguments of these methods.
import abc
#Abstract class
class Base(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def MyMethod(self, a):
'MyMethod prints a'
class Derivative(Base)
def MyMethod(self):
print 'MyMethod'
What happens when an abstract method has parameters? When the subclass implements the method, it must contain all the parameters as well. The subclass' implementation can also add extra parameters if required. We could also use default arguments, you can read about those here.
An abstract method is a method that is declared, but contains no implementation. Abstract classes cannot be instantiated, and require subclasses to provide implementations for the abstract methods.
To define an abstract method we use the @abstractmethod decorator of the abc module. It tells Python that the declared method is abstract and should be overridden in the child classes. We just need to put this decorator over any function we want to make abstract and the abc module takes care of the rest.
ABCMeta metaclass provides a method called register method that can be invoked by its instance. By using this register method, any abstract base class can become an ancestor of any arbitrary concrete class.
The code below is copied from a proxy-class, which works analogous. It checks that all methods are present and that the method signatures are identical. The work is done in _checkImplementation(). Note the two lines starting with ourf and theirf; _getMethodDeclaration() translates the signatures into strings. Here I chose to require both to be exactly identical:
@classmethod
def _isDelegatableIdentifier(cls, methodName):
return not (methodName.startswith('_') or methodName.startswith('proxy'))
@classmethod
def _getMethods(cls, aClass):
names = sorted(dir(aClass), key=str.lower)
attrs = [(n, getattr(aClass, n)) for n in names if cls._isDelegatableIdentifier(n)]
return dict((n, a) for n, a in attrs if inspect.ismethod(a))
@classmethod
def _getMethodDeclaration(cls, aMethod):
try:
name = aMethod.__name__
spec = inspect.getargspec(aMethod)
args = inspect.formatargspec(spec.args, spec.varargs, spec.keywords, spec.defaults)
return '%s%s' % (name, args)
except TypeError, e:
return '%s(cls, ...)' % (name)
@classmethod
def _checkImplementation(cls, aImplementation):
"""
the implementation must implement at least all methods of this proxy,
unless the methods is private ('_xxxx()') or it is marked as a proxy-method
('proxyXxxxxx()'); also check signature (must be identical).
@param aImplementation: implementing object
"""
missing = {}
ours = cls._getMethods(cls)
theirs = cls._getMethods(aImplementation)
for name, method in ours.iteritems():
if not (theirs.has_key(name)):
missing[name + "()"] = "not implemented"
continue
ourf = cls._getMethodDeclaration(method)
theirf = cls._getMethodDeclaration(theirs[name])
if not (ourf == theirf):
missing[name + "()"] = "method signature differs"
if not (len(missing) == 0):
raise Exception('incompatible Implementation-implementation %s: %s' % (aImplementation.__class__.__name__, missing))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With