The abc module

The core method of creating ABCs is defined in the abc module. This module includes the ABCMeta class that provides several features.

First, the ABCMeta class assures that abstract classes can't be instantiated. A subclass that provides all of the required definitions, however, can be instantiated. The metaclass will invoke the abstract class's special method, __subclasshook__(), as a part of processing __new__(). If that method returns NotImplemented, then an exception will be raised to show that the class didn't define all the required methods.

Second, it provides definitions for __instancecheck__() and __subclasscheck__(). These special methods implement the isinstance() and issubclass() built-in functions. They provide the checks to confirm that an object (or a class) belongs to the proper ABC. This includes a cache of subclasses to speed up the testing.

The abc module also includes a number of decorators for creating abstract method functions that must be provided by a concrete implementation of the abstract base class. The most important of these is the @abstractmethod decorator.

If we wanted to create a new abstract base class, we would use something like the following:

from abc import ABCMeta, abstractmethod
class AbstractBettingStrategy(metaclass=ABCMeta):
    __slots__ = ()
    @abstractmethod
    def bet(self, hand):
        return 1
    @abstractmethod
    def record_win(self, hand):
        pass
    @abstractmethod
    def record_loss(self, hand):
        pass
    @classmethod
    def __subclasshook__(cls, subclass):
        if cls is Hand:
            if (any("bet" in B.__dict__ for B in subclass.__mro__)
            and any("record_win" in B.__dict__ for B in subclass.__mro__)
            and any("record_loss" in B.__dict__ for B in subclass.__mro__)
            ):
                return True
        return NotImplemented

This class includes ABCMeta as its metaclass; it also uses the __subclasshook__() method, which checks for completeness. These provide the core features of an abstract class.

This abstraction uses the abstractmethod decorator to define three abstract methods. Any concrete subclass must define these in order to be a complete implementation of the abstract base class.

The __subclasshook__ method requires that all of the three abstract methods be provided by a subclass. This is, perhaps, heavy-handed, since a super-simple betting strategy shouldn't have to provide methods for counting wins and losses.

The subclass hook relies on two internal features of a Python class definition: the __dict__ attribute and the __mro__ attribute. The __dict__ attribute is where the method names and attribute names are recorded for a class definition. This is essentially the body of the class. The __mro__ attribute is the method resolution order. This is the sequence of the superclasses of this class. Since Python uses multiple inheritance, there can be many superclasses, and the order of these superclasses determines the precedence for resolving names.

The following is an example of a concrete class:

class Simple_Broken(AbstractBettingStrategy):
    def bet( self, hand ):
        return 1

The preceding code can't be built because it doesn't provide necessary implementations for all three methods.

The following is what happens when we try to build it:

>>> simple= Simple_Broken()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Simple_Broken with abstract methods record_loss, record_win

The error message indicates that the concrete class is incomplete. The following is a better concrete class that passes the completeness test:

class Simple(AbstractBettingStrategy):
    def bet( self, hand ):
        return 1
    def record_win(self, hand):
        pass
    def record_loss(self, hand):
        pass

We can build an instance of this class and use it as part of our simulation.

As we noted earlier, the bet() method should probably be the only required method. The other two methods should be allowed to default to the single statement pass.