views:

57

answers:

3

Hi!

suppose I want to create an abstract class in python with some methods to be implemented by subclasses. (in Python)

for example:

class Base():
    def f(self):
        print "Hello."
        self.g()
        print "Bye!" 

class A(Base):
    def g(self):
        print "I am A"

class B(Base):
    def g(self):
        print "I am B"

I'd like that if the base class is instantiated and its f() method called, when g() is called, an exception to raise, informing that a subclass should have implemented method g().

What's the usual thing to do here? Should I raise a NotImplementedError? or is there a more specific way of doing it?

Thanks a lot!
Manuel

+2  A: 

Make a method that does nothing, but still has a docstring explaining the interface. Getting a NameError is confusing, and raising NotImplementedError (or any other exception, for that matter) will break proper usage of super.

Aaron Gallagher
how does raising an error break proper usage of `super`? `super` wouldn't get called in this case because the immediate subclass wouldn't call it. Any calls to super further down the inheritance chain would work fine.
aaronasterling
@aaronasterling, why wouldn't the immediate subclass call it? If you have two classes that inherit from Base and implement the method, and one class that inherits from both, only one of the implementations will be called. If both immediate subclasses call `super` (as they should be), then both implementations will be called.
Aaron Gallagher
Good call. I deleted my answer.
aaronasterling
+5  A: 

In Python 2.6 and better, you can use the abc module to make Base an "actually" abstract base class:

import abc

class Base:
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def g(self):
        pass
    def f(self): # &c

this guarantees that Base cannot be instantiated -- and neither can any subclass which fails to override g -- while meeting @Aaron's target of allowing subclasses to use super in their g implementations. Overall, a much better solution than what we used to have in Python 2.5 and earlier!

Side note: having Base inherit from object would be redundant, because the metaclass needs to be set explicitly anyway.

Alex Martelli
hah. I just got a basic implementation of that running! I'll finish it anyways as an exercise and then see how mine stacks up against the official one.
aaronasterling
Just as a side node: in Python 3.x, the metaclass is defined like this: class Base(metaclass=abc.ABCMeta): ...
Fabian Fagerholm
A: 

Peter Norvig has given a solution for this in his Python Infrequently Asked Questions list. I'll reproduce it here. Do check out the IAQ, it is very useful.

## Python
class MyAbstractClass:
    def method1(self): abstract

class MyClass(MyAbstractClass): 
    pass

def abstract():
    import inspect
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    raise NotImplementedError(caller + ' must be implemented in subclass')
Manoj Govindan
@Manoj, notice that **just mentioning** `abstract` as `method1`'s body does nothing at all: you need to **call** it. Anyway, while @Peter's idea is worthwhile for 2.5 and earlier, in 2.6 and later the abc module I recommend is better: the error comes ASAP, as soon as a still-abstract class is **instantiated**, which is always helpful for fixing errors.
Alex Martelli