315

I am having trouble in using inheritance with Python. While the concept seems too easy for me in Java yet up till now I have been unable to understand in Python which is surprising to me at least.

I have a prototype which follow:

class Shape():
   def __init__(self, shape_name):
       self.shape = shape_name

class Rectangle(Shape):
   def __init__(self, name):
       self.shape = name

In the above code how can I make an abstract method that would need to be implemented for all the subclasses?

2
  • 6
    Btw this really was an afterthought in python. abstract interfaces and such were just recently introduced. Since python isn't compiled, you should make your intent clear in documentation instead of abstract classes. Commented Dec 8, 2010 at 0:05
  • Also a very good application for unit testing. As Python is not compiled, I don't begin to trust code until I've unit tested it. Commented Jul 8, 2021 at 15:05

6 Answers 6

373

Before abc was introduced you would see this frequently.

class Base(object):
    def go(self):
        raise NotImplementedError("Please Implement this method")


class Specialized(Base):
    def go(self):
        print "Consider me implemented"
Sign up to request clarification or add additional context in comments.

4 Comments

this is more pythonic than the accepted answer in my opinion, since it follows the python adage "we're all adults here" - if a subclass doesn't implement this type of abstract method, it will have to deal with the consequences
@EmmettJ.Butler But abc should be implemented after all. Am I right?
@Spiderman nope, abc is not for simple base classes, abc is when you need isinstance checks, similar to isinstance(x, number) or isinstance(x, collections.abc.Sequence).
@EmmettJ.Butler But it doesn't provide any immediate feedback. It provides the feedback only after the method was used, which makes this mechanism completely useless as an abstract class.
345

Something along these lines, using ABC

import abc

class Shape(object):
    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def method_to_implement(self, input):
        """Method documentation"""
        return
    

Also read this good tutorial: https://pymotw.com/3/abc/

You can also check out zope.interface which was used prior to introduction of ABC in python.

6 Comments

Does adding this effects the other things as well ?? ie will other part of my class code need to be changed ??
@user506710: The only other part of your code that might need to be changed is if you are already using a metaclass. In this case, just have your metaclass derive from abc.ABCMeta instead of from type and you should be OK. If you don't know what a metaclass is, don't worry about it. :-)
The linked tutorial is much clearer than the Python abc doc (docs.python.org/2/library/abc.html); yet they say the same thing.
This syntax doesn't work in python 3, see this question/answer: stackoverflow.com/a/18513858/1240268.
In python 3, you should use this answer instead. stackoverflow.com/a/13646263/5093308
|
49

See the abc module. Basically, you define __metaclass__ = abc.ABCMeta on the class, then decorate each abstract method with @abc.abstractmethod. Classes derived from this class cannot then be instantiated unless all abstract methods have been overridden.

If your class is already using a metaclass, derive it from ABCMeta rather than type and you can continue to use your own metaclass.

A cheap alternative (and the best practice before the abc module was introduced) would be to have all your abstract methods just raise an exception (NotImplementedError is a good one) so that classes derived from it would have to override that method to be useful.

However, the abc solution is better because it keeps such classes from being instantiated at all (i.e., it "fails faster"), and also because you can provide a default or base implementation of each method that can be reached using the super() function in derived classes.

4 Comments

you can provide a default or base implementation of each method that can be reached using the super() function in derived classes you can't use super() without abc?
What it's saying is that you must use super() to reach method implementations in an ABC, not that you need to use abc in order to use super(). super() works with any new-style class.
I was only confused because it was "abc is better for motivation 1 and motivation 2" but motivation 2 is not abc specific :)
motivation 2 is abc-specific in that the "raise an exception in the base class methods" technique doesn't play nice with having then do something useful.
14

Abstract base classes are deep magic. Periodically I implement something using them and am amazed at my own cleverness, very shortly afterwards I find myself completely confused by my own cleverness (this may well just be a personal limitation though).

Another way of doing this (should be in the python std libs if you ask me) is to make a decorator.

def abstractmethod(method):
    """
    An @abstractmethod member fn decorator.
    (put this in some library somewhere for reuse).

    """
    def default_abstract_method(*args, **kwargs):
        raise NotImplementedError('call to abstract method ' 
                                  + repr(method))
    default_abstract_method.__name__ = method.__name__    
    return default_abstract_method


class Shape(object):

    def __init__(self, shape_name):
       self.shape = shape_name

    @abstractmethod
    def foo(self):
        print "bar"
        return

class Rectangle(Shape):
    # note you don't need to do the constructor twice either
    pass  

r = Rectangle("x")
r.foo()

I didn't write the decorator. It just occurred to me someone would have. You can find it here: http://code.activestate.com/recipes/577666-abstract-method-decorator/ Good one jimmy2times. Note the discussion at the bottom of that page r.e. type safety of the decorator. (That could be fixed with the inspect module if anyone was so inclined).

2 Comments

How does this differ from abc.abstractmethod?
Not a great deal. Under the hood they're not too different I imagine. Pragmatically: "Using the abc.abstractmethod decorator requires that the class’s metaclass is ABCMeta or is derived from it.".
7

You can't, with language primitives. As has been called out, the abc package provides this functionality in Python 2.6 and later, but there are no options for Python 2.5 and earlier. The abc package is not a new feature of Python; instead, it adds functionality by adding explicit "does this class say it does this?" checks, with manually-implemented consistency checks to cause an error during initialization if such declarations are made falsely.

Python is a militantly dynamically-typed language. It does not specify language primitives to allow you to prevent a program from compiling because an object does not match type requirements; this can only be discovered at run time. If you require that a subclass implement a method, document that, and then just call the method in the blind hope that it will be there.

If it's there, fantastic, it simply works; this is called duck typing, and your object has quacked enough like a duck to satisfy the interface. This works just fine even if self is the object you're calling such a method on, for the purposes of mandatory overrides due to base methods that need specific implementations of features (generic functions), because self is a convention, not anything actually special.

The exception is in __init__, because when your initializer is being called, the derived type's initializer hasn't, so it hasn't had the opportunity to staple its own methods onto the object yet.

If the method was't implemented, you'll get an AttributeError (if it's not there at all) or a TypeError (if something by that name is there but it's not a function or it didn't have that signature). It's up to you how you handle that- either call it programmer error and let it crash the program (and it "should" be obvious to a python developer what causes that kind of error there- an unmet duck interface), or catch and handle those exceptions when you discover that your object didn't support what you wish it did. Catching AttributeError and TypeError is important in a lot of situations, actually.

7 Comments

What about the abc module mentioned in the other answer then ??
For what it's worth, Python is strongly typed, it's just dynamically typed.
Ack. This is the first time I'd heard of the abc module. I'm leaving this answer, though, because it applies to versions of Python before 2.6 (CentOS ships with 2.4), and duck typing still works here.
Yeah, it's a good point about the duck typing. Generally, programming in Python, you will generally be happier just calling the methods you expect rather than enforcing real type constraints. The abc is a nice option to specify what kind of duck you want, though.
python certainly is strongly typed. he is referring to static vs. dynamic typing.
|
7

You can use six and abc to construct a class for both python2 and python3 efficiently as follows:

import six
import abc

@six.add_metaclass(abc.ABCMeta)
class MyClass(object):
    """
    documentation
    """

    @abc.abstractmethod
    def initialize(self, para=None):
        """
        documentation
        """
        raise NotImplementedError

This is an awesome document of it.

Comments