Search code examples
pythonnaming-conventionsabstract-class

Python abstract classes - how to discourage instantiation?


I come from a C# background where the language has some built in "protect the developer" features. I understand that Python takes the "we're all adults here" approach and puts responsibility on the developer to code thoughtfully and carefully.

That said, Python suggests conventions like a leading underscore for private instance variables. My question is, is there a particular convention for marking a class as abstract other than just specifying it in the docstrings? I haven't seen anything in particular in the python style guide that mentions naming conventions for abstract classes.

I can think of 3 options so far but I'm not sure if they're good ideas:

  1. Specify it in the docstring above the class (might be overlooked)
  2. Use a leading underscore in the class name (not sure if this is universally understood)
  3. Create a def __init__(self): method on the abstract class that raises an error (not sure if this negatively impacts inheritance, like if you want to call a base constructor)

Is one of these a good option or is there a better one? I just want to make sure that other developers know that it is abstract and so if they try to instantiate it they should accept responsibility for any strange behavior.


Solution

  • If you're using Python 2.6 or higher, you can use the Abstract Base Class module from the standard library if you want to enforce abstractness. Here's an example:

    from abc import ABCMeta, abstractmethod
    
    class SomeAbstractClass(object):
        __metaclass__ = ABCMeta
    
        @abstractmethod
        def this_method_must_be_overridden(self):
            return "But it can have an implementation (callable via super)."
    
    class ConcreteSubclass(SomeAbstractClass):
        def this_method_must_be_overridden(self):
            s = super(ConcreteSubclass, self).this_method_must_be_overridden()
            return s.replace("can", "does").replace(" (callable via super)", "")
    

    Output:

    >>> a = SomeAbstractClass()
    Traceback (most recent call last):
      File "<pyshell#13>", line 1, in <module>
        a = SomeAbstractClass()
    TypeError: Can't instantiate abstract class SomeAbstractClass with abstract
    methods this_method_must_be_overridden
    >>> c = ConcreteSubclass()
    >>> c.this_method_must_be_overridden()
    'But it does have an implementation.'