I often see classes implemented like this and just wondering why? Even if it was a base class, this doesn't create an interface that the child class can follow.

class AnAbstractBaseCLass:

2 Answers

Blckknght On

It can be useful to have an base class like what you show if instances of subclasses might be mixed in with instances of other non-derived classes and you want to easily tell them apart.

class Base: pass  # empty base class

class Derived1(Base): pass # normally this would have contents, but it's empty for this example
class Derived2(Base): pass

class OtherClass: pass # not derived from Base

mixed_list = [Derived1(), Derived2(), OtherClass()]

filtered_list = [obj for obj in mixed_list if isinstance(obj, Base)]

This might not be all that valuable though, because the derived classes are not guaranteed to have any interfaces in common, so the filtered_list might be impossible to get good use out of (since you can't call any common method on its values). But it's possible and maybe even likely that there is some common interface, it's just not anything that's enforced by the base class (with the abc module).

jferard On

Maybe this is something analog to Java's marker interfaces. E.g. RandomAccess is a void interface (no methods):

Marker interface used by List implementations to indicate that they support fast (generally constant time) random access. The primary purpose of this interface is to allow generic algorithms to alter their behavior to provide good performance when applied to either random or sequential access lists.

Whether a list supports fast random access or not does not affect the interface of the list but the performance of the list.

More generally, an interface or a base class, as a set of public methods (whatever "public" really means in Python), is a kind of functional contract, but does not say anything about non functional matters (see What is the difference between functional and non functional requirement?). Most of the times, we know exactly the type of the object we use, but sometimes, due to polymorhism, we don't know. Yet we might need some non functional information, and a void base class may be a good solution:

if isinstance(L, RandomAccess):
    # I can use L[i] without performance penalty 
    # I will use an iterator