Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract methods with specific arguments in Python

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'
like image 472
Konstantin Avatar asked Mar 22 '14 18:03

Konstantin


People also ask

Can abstract method have parameters in Python?

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.

What is Python Abstractmethod?

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.

How do you create an abstract method in Python?

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.

What is ABCMeta?

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.


1 Answers

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))
like image 109
user508402 Avatar answered Oct 16 '22 10:10

user508402