0

One of the ways to cope with the static nature of Singeltons is to hide them behind interfaces. This allows to use Singletons in some clients, but to replace them with substitutes such as Mocks in tests.

Can I make a Python Metaclass Singleton implement an interface?

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class ILogger(ABC):
    @abstractmethod
    def log(self,message: str) -> None:
        pass

class Logger(ILogger,metaclass=Singleton): # won't compile - meta mismatch
    def log(self,message: str) -> None:
        print("Real Log: ",message)

class FakeLogger(ILogger):
    def log(self,message: str) -> None:
        print("Fake Log: ",message)


def task1(logger: ILogger):
    print("using logger ",id(logger))
    logger.log("Task1 error 1 on log ")

When I try I get the following error

metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Do I need to switch to a different python implementation of Singleton such as overriding __new__ to allow the Singleton to implement an interface?

Gonen I
  • 5,576
  • 1
  • 29
  • 60
  • This kind of thing is one of the reasons not to use a metaclass unless you really have to. In this case, a metaclass is serious overkill for the job of just making one instance of a class. – user2357112 Oct 21 '21 at 20:14
  • Plus, the metaclass [fails at its one job](https://ideone.com/GB0Tl7). – user2357112 Oct 21 '21 at 20:15

0 Answers0